swift - significa - traducir al español
Utilizar operador lógico como cierre de cosechadora en reducir. (5)
Aquí hay otro enfoque, modifiqué la función reduceBools para tomar al operador como un parámetro:
typealias LogicalOperator = ((Bool, @autoclosure () throws -> Bool) throws -> Bool)
func reduceBools(values: [Bool], combine: LogicalOperator) -> Bool {
var started: Bool = false
return values.reduce(into: true, { (result, value) in
result = started ? try! combine(result, value) : value // obviously up to you how you''d handle the try/catch
started = true
})
}
let bools = [true, false, false, true]
let result1 = self.reduceBools(values: bools, combine: ||)
print(result1) // prints true
let result2 = self.reduceBools(values: bools, combine: &&)
print(result2) // prints false
O podría ser más útil como una extensión de la secuencia.
extension Sequence where Element == Bool {
func reduce(_ combine: LogicalOperator) -> Bool {
var started: Bool = false
return self.reduce(into: true, { (result, value) in
result = started ? try! combine(result, value) : value
started = true
})
}
}
print(bools.reduce(||)) // prints true
Estoy tratando de reducir una matriz de Bool
mediante la aplicación del operador lógico OR ( ||
) usando el siguiente código, sin embargo, aparece un error:
func reduceBools(values: [Bool]) -> Bool {
return values.reduce(false, combine: ||)
}
Referencia ambigua al miembro ''||''
Análogamente para los enteros, el código funciona como un encanto.
func reduceInts(values: [Int]) -> Int {
return values.reduce(0, combine: +)
}
Pude hacerlo funcionar agregando un ||
función (código abajo) o usando un { $0 || $1 }
{ $0 || $1 }
cierre, pero me disgustan estos enfoques y preferiría simplemente pasar el operador.
func ||(lhs: Bool, rhs: Bool) -> Bool {
return lhs || rhs
}
Lo mismo sucede con el operador lógico AND ( &&
).
¿Cómo puedo hacer que funcione sin usar el truco anterior?
Como alternativa, podrías utilizar el siguiente enfoque.
// ||
func reduceBoolsOr(values: [Bool]) -> Bool {
return values.contains(true)
}
// &&
func reduceBoolsAnd(values: [Bool]) -> Bool {
return !values.contains(false)
}
Tenga en cuenta que .reduce
viene con una sobrecarga . Si el resultado final es la importancia de su pregunta (en lugar de indagar sobre el comportamiento inesperado de los operadores ||
y &&
en este contexto), tal vez el enfoque pragmático anterior pueda ser de ayuda, incluso si realmente no reduce la matriz. Sin embargo, produce el mismo resultado debido a la naturaleza simple del tipo booleano.
El siguiente enfoque funcionará
values.reduce(false) { $0 || $1 }
Esto sucede debido a la semántica de cierre de Swifts. Toma sus argumentos y les aplica una función, omitiendo los nombres de los argumentos.
protocol Numeric {
...
public static func +(lhs: Self, rhs: Self) -> Self
...
}
En el ejemplo con Ints, pasaría (Int, Int) a un cierre, y la función + en el protocolo Numérico espera exactamente dos ints para sumarlos.
Es por eso que el código como el siguiente funciona bien
[1, 2, 3, 4].reduce(0, +)
Porque acabas de tomar 2 ints, y la función aplicada, que toma solo dos ints. Si escribes tu propia función, que tomaría solo dos argumentos, también funcionaría.
func myOwnAwesomeFunc<T: Numeric>(a: T, b: T) -> T { in
return 1 // production ready
}
[1, 2, 3, 4].reduce(0, myOwnAwesomeFunc) // prints 1
Bien hasta ahora. Pero ¿por qué no podemos escribir
[true, false, true].reduce(false, ||) // yields Cannot invoke ''reduce''
// with an argument list of type
// ''(Bool, (Bool, @autoclosure () throws -> Bool) throws -> Bool)''
Eso es porque este operador toma bool y un cierre, que devuelve bool. No bool, cierre! Pero si es así, ¿por qué no estamos escribiendo true || { false }()
true || { false }()
? Eso es debido a @autoclosure, que se encarga de los frenillos para nosotros.
Pregunta principal, ¿por qué se implementa de esta manera, por lo que no podemos usar la impresionante sintaxis de cierre de mano corta de Swifts con booleanos? Idk
Referencia ambigua al miembro ''||'' significa que hay más de un candidato posible, entre los cuales el compilador no puede elegir. En tu caso esos son
public func ||<T : BooleanType, U : BooleanType>(lhs: T, @autoclosure rhs: () throws -> U) rethrows -> Bool
y
public func ||<T : BooleanType>(lhs: T, @autoclosure rhs: () throws -> Bool) rethrows -> Bool
probablemente tu ''hack'' usando un { $0 || $1 }
{ $0 || $1 }
es la mejor solución aquí.