10

Я пытаюсь уменьшить массив Bool с применением логического оператора ИЛИ (||), используя следующий код, но я получаю сообщение об ошибке:Использование логического оператора объединить замыкание в сократить

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

Ambiguous reference to member '||'

Аналогично для целых чисел код работает как шарм.

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

Я был в состоянии сделать его работу, добавив || функцию (код ниже) или с помощью { $0 || $1 } закрытия, но я не люблю эти подходы, и я предпочел бы просто передав оператору.

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

То же самое происходит и для логического И (&&) оператора.

Как я могу заставить его работать без использования взлома выше?

+3

Это кажется ошибка/ограничение из-за "autoclosure" параметров '||' и '' &&. Сравните http://stackoverflow.com/questions/28648268/what-is-the-type-of-the-logical-operators и следующие комментарии. –

+0

@MartinR Спасибо за ссылку! я думал, что я просто глупый человек ... – user3441734

+0

@MartinR, похоже, что это так:/Есть ли какой-нибудь rdar на нем, чтобы я мог обмануть его? – fpg1503

ответ

15

В качестве альтернативы можно использовать следующий подход

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

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

Обратите внимание, что .reducecomes with an overhead. Если конечный результат - это важность вашего вопроса (вместо того, чтобы расспрашивать о неожиданном поведении операторов ||10 и && в этом контексте), тогда, возможно, прагматичный подход выше может помочь, даже если он действительно не уменьшает массив, но при этом получается тот же результат из-за простой природы булевого типа.

+1

Я бы сказал, что использование содержимого в этом случае еще лучше, потому что вы описываете результат, который вам нужен чтобы получить, а не как вычислить его. Это еще более декларативный, чем обычный функциональный подход. :) –

1

Неоднозначная ссылка на член '||' означает, что существует несколько возможных кандидатов, из которых компилятор не может выбрать. В вашем случае это те

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 } это лучшие решения здесь.

+0

Похоже, единственная причина для второго заключается в том, что первый из них не может быть '@ _transparent' из-за ошибки. Самое безумие в том, что их реализации идентичны. – fpg1503

0

Это происходит из-за семантики закрытия Swifts. Он принимает ваши аргументы и применяет к ним функцию, опуская имена аргументов.

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

В примере с Ints, вы бы пройти (Int, Int) в замыкание и + функция в числовой протокол ожидает ровно два Интс подвести их.

Вот почему код, как показано ниже работает просто отлично

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

Потому что вы просто взяли 2 Интс, и применяется функция, которая принимает только два Интс. Если вы напишете свою собственную функцию, которая займет всего два аргумента, она будет работать.

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 }()? Thats из-за @autoclosure, которая заботится о фигурных скобках для нас.

Главный вопрос, почему он реализован таким образом, поэтому мы не можем использовать Swifts awesome short-hand syntax с булевыми? ИДК

-1

После подход будет работать

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