10

Sto cercando di ridurre una serie di Bool s applicando l'operatore logico OR (||) utilizzando il seguente codice, tuttavia si ottiene un errore:Uso operatore logico come combinare chiusura nel ridurre

func reduceBools(values: [Bool]) -> Bool { 
    return values.reduce(false, combine: ||) 
} 

Ambiguous reference to member '||'

Analogamente per i numeri interi il codice funziona come un incantesimo.

func reduceInts(values: [Int]) -> Int { 
    return values.reduce(0, combine: +) 
} 

sono stato in grado di farlo funzionare con l'aggiunta di una funzione || (codice qui sotto) o con una chiusura { $0 || $1 } ma non mi piace questi approcci e preferirei semplicemente passando l'operatore.

func ||(lhs: Bool, rhs: Bool) -> Bool { 
    return lhs || rhs 
} 

La stessa cosa succede per l'operatore logico AND (&&).

Come posso farlo funzionare senza utilizzare l'hack sopra?

+3

Questo sembra essere un bug/limitazione dovuta ai parametri "autoclosure" di '||' e '' &&. Confronta http://stackoverflow.com/questions/28648268/questo-è-il-tipo-del-commercial-operatori e i seguenti commenti. –

+0

@ MartinR grazie per il collegamento! Stavo pensando, che sono solo un uomo stupido ... – user3441734

+0

@ Martin che sembra essere il caso:/C'è qualche rdar su di esso in modo che possa ingannarlo? – fpg1503

risposta

15

In alternativa, è possibile utilizzare il seguente approccio

// || 
func reduceBoolsOr(values: [Bool]) -> Bool { 
    return values.contains(true) 
} 

// && 
func reduceBoolsAnd(values: [Bool]) -> Bool { 
    return !values.contains(false) 
} 

noti che .reducecomes with an overhead. Se il risultato è l'importanza della tua domanda (piuttosto che indagare sopra il comportamento imprevisto degli operatori || e && in questo contesto), allora forse l'approccio pragmatico di cui sopra può essere di aiuto, anche se in realtà non riduce il array, tuttavia producendo lo stesso risultato a causa della natura semplice del tipo booleano.

+1

Direi che l'utilizzo di contiene è ancora meglio in questo caso, perché stai descrivendo il risultato che vuoi per ottenere, piuttosto che come calcolarlo. È persino più dichiarativo del solito approccio funzionale. :) –

1

Riferimento ambiguo al membro '||' significa che ci sono più candidati possibili, da cui il compilatore non è in grado di scegliere. Nel tuo caso questi sono

public func ||<T : BooleanType, U : BooleanType>(lhs: T, @autoclosure rhs:() throws -> U) rethrows -> Bool 

e

public func ||<T : BooleanType>(lhs: T, @autoclosure rhs:() throws -> Bool) rethrows -> Bool 

probabilmente la 'mod' utilizzando un { $0 || $1 } è delle migliori soluzioni qui.

+0

Sembra che l'unico motivo per il secondo sia che il primo non può essere "@ _transparente" a causa di un bug. La cosa più folle è che le loro implementazioni sono identiche. – fpg1503

0

Questo succede a causa della semantica di chiusura Swifts. Prende i tuoi argomenti e applica loro la funzione, omettendo i nomi degli argomenti.

protocol Numeric { 
    ... 
    public static func +(lhs: Self, rhs: Self) -> Self 
    ... 
} 

Nell'esempio con Ints, si potrebbe passare (Int, Int) in una chiusura, e + funzione nel protocollo numerico si aspetta esattamente due interi per riassumere loro.

Ecco perché il codice come di seguito funziona bene

[1, 2, 3, 4].reduce(0, +) 

Perché hai appena preso 2 int, e la funzione, che prende solo due interi applicata. Se si scrive la propria funzione, che richiederebbe solo due argomenti, funzionerebbe altrettanto bene.

func myOwnAwesomeFunc<T: Numeric>(a: T, b: T) -> T { in 
    return 1 // production ready 
} 

[1, 2, 3, 4].reduce(0, myOwnAwesomeFunc) // prints 1 

Buono finora.Ma perché non possiamo scrivere

[true, false, true].reduce(false, ||) // yields Cannot invoke 'reduce' 
// with an argument list of type 
// '(Bool, (Bool, @autoclosure() throws -> Bool) throws -> Bool)' 

Questo perché questo operatore prende bool e una chiusura, che restituisce bool. Non bool, chiusura! Ma se è così, perché non scriviamo true || { false }()? Questo è dovuto a @autoclosure, che si prende cura delle parentesi graffe per noi.

Domanda principale, perché è implementata in questo modo, quindi non possiamo usare la sintassi di chiusura a mano corta di Swifts con i booleani? Idk

-1

Seguendo approccio funziona

values.reduce(false) { $0 || $1 } 
Problemi correlati