Questo è ambiguo perché Int
è sia Hashable
sia Comparable
e nessuno di questi due protocolli si trova nella stessa gerarchia. (È possibile visualizzare il Int
protocol hierarchy on Swifter.)
func f<T: Hashable>(t: T) {
println("Hashable: \(t)")
}
func f<T: Comparable>(t: T) {
println("Comparable: \(t)")
}
let number = 5
f(number)
// error: ambiguous use of 'f'
Non si può dire esplicitamente quale funzione chiamare, a causa dei requisiti di tipo associato di ogni protocollo, ma quello che si può fare è definire una terza funzione :
func f<T: Comparable where T: Hashable>(t: T) {
println("Both Hashable & Comparable: \(t)")
}
f(number)
// Both Hashable & Comparable: 5
Così Swift implements il ..<
operatore, che altrimenti sarebbe ambiguo per i tipi che implementano sia Comparable
e ForwardIndexType
.
Per espandere un po 'più avanti, ecco uno sguardo a ciò che intende per "non si può dire che in modo esplicito quale funzione chiamare, a causa dei requisiti di tipo associato di ogni protocollo." Protocolli possono essere usati come tipi, come descritto nel libro Swift chapter on Protocols:
protocol RandomNumberGenerator {
func random() -> Double
}
class Dice {
let generator: RandomNumberGenerator
// ...
}
In questo esempio, la proprietà generatore può essere qualsiasi tipo conforme a RandomNumberGenerator
- simile a come id<ProtocolName>
viene utilizzato in Objective-C. Tuttavia, i protocolli possono solo essere utilizzati come tipi quando non includono un tipo o riferimento Self
nella dichiarazione. Questo purtroppo esclude quasi tutti i tipi di built-in in Swift, tra cui Hashable
e Comparable
.
Hashable
eredita da Equatable
, che fa riferimento Self
per la definizione del ==
esercente:
func ==(lhs: Self, rhs: Self) -> Bool
e Comparable
fa lo stesso con i suoi gestori:
func <=(lhs: Self, rhs: Self) -> Bool
// similar definitions for <, >, and >=
Questi protocolli possono solo essere utilizzati come vincoli generici e non usati come tipo quando si dichiara una variabile. (Per quanto posso dire questo non è documentato, ma è individuabile attraverso i messaggi di errore.)
Due protocolli che Non hanno tale restrizione sono Printable
e BooleanType
, in modo che possiamo osservare come funzionano. Bool
è l'unico tipo integrato conforme a BooleanType
ed è anche Printable
, quindi questo sarà il nostro tipo di test. Ecco le nostre funzioni generiche p()
e la variabile t
- notare che, come prima, non possiamo semplicemente chiamare la funzione con t
:
func p<T: Printable>(t: T) {
println("Printable: \(t)")
}
func p<T: BooleanType>(t: T) {
println("BooleanType: \(t)")
}
let t: Bool = true
p(t)
// error: Ambiguous use of 'p'
Invece, abbiamo bisogno di lanciare (upcast?) t
ad un particolare protocollo utilizzando la parola chiave as
, e chiamare una particolare funzione generica in questo modo:
p(t as Printable)
// Printable: true
p(t as BooleanType)
// BooleanType: true
Quindi, fintanto che abbiamo un protocollo di qualifica, siamo in grado di scegliere quale variante del metodo generico da chiamare.
Il lavoro '(myInt as Hashable)' funziona? –
No :(Ottengo 2 errori: 'Protocollo 'Hashable' può essere usato solo come un vincolo generico perché ha i requisiti di tipo Self o assosiated' AND 'Type' Hashable 'non è conforme al protocollo' Comparable'' (questo uno suona strano :)) –
FYI per l'ultima nota rapida queste due grandi risposte ... http://stackoverflow.com/a/39836054/294884 ... http://stackoverflow.com/a/39835658/294884 – Fattie