2016-01-02 10 views
7

Sto provando a confrontare due tipi di protocollo utilizzando il confronto di riferimento (===). Quando faccio ricevo (dove Foo è un protocollo):Swift - L'operatore binario '===' non può essere applicato a due protocolli

Binary operator '===' cannot be applied to two 'Foo' operands 

capisco perché == won't work without conforming to Equatable, ma in questo caso sto usando ===, che è solo un confronto di indirizzi.

+2

Sono questi classe protocolli? '===' funzionerà solo sui tipi di classe, non sui tipi di valore (structs, enum). Se il protocollo non è dichiarato come protocollo di classe, non funzionerà perché il compilatore non può sapere che stai confrontando le classi e non le strutture. – Sulthan

+0

@Sulthan Buon punto. Ma alla fine non tutti i protocolli saranno conformi a una classe? –

+0

No, poiché le strutture, ad esempio, possono essere conformi anche ai protocolli – luk2302

risposta

2

=== comparatore è per confrontare i riferimenti - poiché le strutture sono tipi di valore passano per valore e non hanno riferimenti. (essenzialmente passare una struttura ne prende una copia)

Le classi vengono passate per riferimento: l'istanza viene archiviata in memoria in modo da poter utilizzare il comparatore ===.

Quindi sì è possibile confrontarli, ma è necessario assicurarsi che il protocollo sia limitato solo alle classi.

ad es.

//: Playground - noun: a place where people can play 

protocol Foo: class { 

} 

class A: Foo { 

} 

class B: Foo { 

} 

let a: Foo = A() 
let b: Foo = A() 
let c: Foo = B() 

a === a // true 
a === b // false 
a !== c // true 
b === c // false 
c === c // true 

dove

struct B: Foo { 

} 

non riuscirebbe a compilare

+0

, si confrontano i riferimenti alle istanze di classe os, non al protocollo. – user3441734

+0

@ user3441734 Sono convertiti nel tipo di protocollo - stai dicendo al compilatore che tutto ciò che sai della variabile è che è conforme a Foo. Non sa che aeb è di istanza A. –

+0

"stai dicendo al compilatore che tutto ciò che sai della variabile è che è conforme a Foo" è vero! ma hai ancora un'istanza del tipo di classe o di struttura, ecc. controlla il .dynamicType della variabile che si conforma al protocollo e hai assegnato il suo valore ad alcune classi o struct ecc. – user3441734

-6

con === è possibile confrontare due riferimenti per alcuni casi, ma il tipo di protocollo non può essere istanziato!

protocol P {} 
class C: P{} 
let c = C() 
let p:P = C() 
c.dynamicType // C.Type 
p.dynamicType // C.Type 

e

let p:P = P() // error !!! 

Si può dire al compilatore che il protocollo è il protocollo di classe

protocol P: class {} 
class C: P{} 
struct S: P{} // error: non-class type 'S' cannot conform to class protocol 'P' 

per essere sicuri che non v'è alcun tipo di valore che si conforma ad esso

vedere l'ultimo esempio

protocol P: class {} 
class C: P{} 
let c = C() 
let p:P = c 

p === c // true !! 
let p1:P = c 

p === p1 // true !!! 

l'operatore === lavora qui

let c1 = C() 
let p2:P = c1 

p2 === p1 // false !! 
+0

hai ragione, ma allo stesso tempo questo non fornisce alcun aiuto. Dal momento che è ancora possibile avere istanze di protocolli "downcasting" un'istanza di una classe conforme al protocollo. – luk2302

+0

@ luk2302 è possibile confrontare i riferimenti alle istanze di classe, non le istanze del tipo di protocollo. anche se qualcuno non è d'accordo, questa è la realtà. non sei in grado di creare un'istanza di protocollo. – user3441734

+0

@ luk2302 downcasting non cambia dynamicType. downcasting può aiutarti a lavorare con il tipo in quanto è un'istanza di protocollo (nascondendo tutte le classi o struct ... implementazione specifica), ma hai ancora un'istanza di dynamicType 'originale' – user3441734

5

Facciamo vedere il problema sulle dichiarazioni:

L'operatore === è dichiarato per AnyObject.

public func ===(lhs: AnyObject?, rhs: AnyObject?) -> Bool 

Che cosa è esattamente AnyObject? AnyObject è un protocollo a cui tutte le classi si conformano automaticamente.

In Swift, non ci sono solo tipi di classe, ci sono anche tipi di valore, per esempio le strutture e le enumerazioni. Tutti possono essere conformi ai protocolli, ma le strutture e le enumerazioni non sono conformi allo standard AnyObject. Dato che hai uno sfondo Java, il comportamento dei tipi di valore è simile ai tipi primitivi in ​​Java: vengono passati per valore (copia) e di solito non si ottiene un riferimento.

Quando si dichiara un protocollo, il compilatore non sa se verrà adottato da classi o strutture.

protocol X {} 

struct A: X {} 

let x1: X = A() 
let x2: X = A() 

// PROBLEM - we cannot compare two structs by === 
if x1 === x2 { 
} 

Ciò significa che dobbiamo dire al compilatore che il protocollo possa essere adottato solo per classi:

protocol X: AnyObject {} 

o

protocol X: class {} 

Poi

class A: X {} // can be adopted only by classes 

let x1: X = A() 
let x2: X = A() 

// NO problem 
if x1 === x2 { 
} 
+0

Non si sta eseguendo il confronto utilizzando la definizione del protocollo, solo la definizione della classe: è necessario eseguire il cast o indicare al compilatore il tipo anziché consentirne l'inferenza. –

+0

@OliverAtkinson Hai ragione. – Sulthan

+0

=== l'operatore è definito lì, nel protocollo AnyObject. Ancora non sei in grado di creare un'istanza di AnyObject. prova a farlo e fammi sapere ... – user3441734

Problemi correlati