Использовать логический оператор как комбинацию закрытия в сокращении
Я пытаюсь уменьшить массив Bool
, применяя логический оператор ИЛИ (||
), используя следующий код, однако я получаю сообщение об ошибке:
func reduceBools(values: [Bool]) -> Bool {
return values.reduce(false, combine: ||)
}
Неоднозначная ссылка на член '||'
Аналогично для целых чисел код работает как шарм.
func reduceInts(values: [Int]) -> Int {
return values.reduce(0, combine: +)
}
Мне удалось заставить его работать, добавив функцию ||
(код ниже) или используя закрытие { $0 || $1 }
, но мне не нравятся эти подходы, и я предпочел бы просто передать оператор.
func ||(lhs: Bool, rhs: Bool) -> Bool {
return lhs || rhs
}
То же самое происходит для логического оператора И (&&
).
Как я могу заставить его работать без использования взлома выше?
Ответы
Ответ 1
В качестве альтернативы вы можете использовать следующий подход
// ||
func reduceBoolsOr(values: [Bool]) -> Bool {
return values.contains(true)
}
// &&
func reduceBoolsAnd(values: [Bool]) -> Bool {
return !values.contains(false)
}
Обратите внимание, что .reduce
поставляется с накладными расходами. Если конечным результатом является важность вашего вопроса (а не выяснение выше неожиданного поведения операторов ||
и &&
в этом контексте), то, возможно, прагматичный подход выше может помочь, даже если он действительно не уменьшите массив, однако, получив тот же результат из-за простой природы булевого типа.
Ответ 2
Неоднозначная ссылка на член '||' означает, что существует несколько возможных кандидатов, из которых компилятор не может выбрать. В вашем случае это
public func ||<T : BooleanType, U : BooleanType>(lhs: T, @autoclosure rhs: () throws -> U) rethrows -> Bool
и
public func ||<T : BooleanType>(lhs: T, @autoclosure rhs: () throws -> Bool) rethrows -> Bool
Вероятно, ваш "взлом" с помощью { $0 || $1 }
является лучшим решением здесь.
Ответ 3
Это происходит из-за семантики закрытия Swifts. Он принимает ваши аргументы и применяет к ним функцию, опуская имена аргументов.
protocol Numeric {
...
public static func +(lhs: Self, rhs: Self) -> Self
...
}
В примере с Ints вы передадите (Int, Int) в замыкание, а функция + в числовом протоколе ожидает ровно два ints, чтобы их суммировать.
Вот почему код, как показано ниже, работает просто отлично
[1, 2, 3, 4].reduce(0, +)
Потому что вы просто взяли 2 ints и прикладную функцию, которая занимает всего два ints.
Если вы напишете свою собственную функцию, которая будет принимать только два аргумента, она также будет работать.
func myOwnAwesomeFunc<T: Numeric>(a: T, b: T) -> T { in
return 1 // production ready
}
[1, 2, 3, 4].reduce(0, myOwnAwesomeFunc) // prints 1
Хорошо. Но почему мы не можем писать
[true, false, true].reduce(false, ||) // yields Cannot invoke 'reduce'
// with an argument list of type
// '(Bool, (Bool, @autoclosure () throws -> Bool) throws -> Bool)'
Это потому, что этот оператор принимает bool и замыкание, которое возвращает bool. Не bool, закрытие!
Но если это так, почему мы не пишем true || { false }()
?
Это из-за @autoclosure, которая заботится о фигурных скобках для нас.
Основной вопрос, почему он реализован таким образом, поэтому мы не можем использовать Swifts awesome short-hand syntax with booleans? ИДК
Ответ 4
Следующий подход будет работать
values.reduce(false) { $0 || $1 }