2016-01-11 2 views
4

Сегодня я видел некоторые примеры Swift 2,0 (Xcode 7,2) код, который можно резюмировать следующим образом:Почему этот фрагмент кода Swift компилируется? Как это работает?

let colours = ["red", "green", "blue"] 
let r1 = colours.contains("The red one.".containsString) // true 
let y1 = colours.contains("The yellow one.".containsString) // false 

я ожидал бы ошибку компиляции из-за отсутствия скобки на функции containsString(). На самом деле, я даже не знаю, как работает рекурсия. Строки, рекурсивные через каждый элемент массива colours или наоборот?

Любое объяснение оценено.

ответ

6

То, что вы на самом деле делаете вызов метода .contains(predicate: String -> Bool) (фактический метод может бросить, но это не имеет значения здесь)

Это означает, что вы просите массив colours, если он содержит элемент, который соответствует этому предикату , который составляет "The red one.".containsString. Таким образом, массив проверяет свои элементы один за другим и проверяет его на наличие этого предиката. Если он найдет один, он вернет true, иначе он вернет false.

Код выше делает это:

"The red one.".containsString("red") 
"The red one.".containsString("green") 
"The red one.".containsString("blue") 

"The yellow one.".containsString("red") 
"The yellow one.".containsString("green") 
"The yellow one.".containsString("blue") 

И он проверяет, если он получил true где-то.

+0

Замечательное замечание: я думал о C, что бы совершенно по-другому, оно проверит, содержит ли массив строк функцию, и компилятор скажет вам, что каждый раз будет возвращать false – vrwim

+0

Два хороших ответа (и немного чтения в выходные) помогли мне понять, что происходит. Я не заметил, что функция Array.contains была перегружена: –

+0

... ни взаимосвязь между функциями и замыканиями (и реальное значение наличия функций как «граждан первого класса» на языке). Наконец, функциональное программирование становится немного яснее. В идеале я бы ответил на оба ответа, но я собираюсь на @vrwin (только потому, что у него более низкий представитель. Гол). Спасибо, оба. –

5

В Swift функции могут быть названы закрытыми. Цитируя Apple documentation на закрытий:

Глобальные и вложенные функции, как и введены в функции, на самом деле являются частными случаями закрытия

Однако containsString() является метод экземпляра (спасибо Martin R для наблюдения). Код работает, потому что instance methods in Swift are actually curried functions, которые попадают в категорию названного закрытия.

Что происходит, что "The red one.".containsString транслируется в глобальной функции, как это:

String.containsString("The red one.") 

, которая возвращает функцию (String) -> Bool, которая заканчивается тем, что был вызван contains, как это:

String.containsString("The red one.")("red") 
String.containsString("The red one.")("green") 
String.containsString("The red one.")("blue") 

Теперь, с учетом подписи contains:

public func contains(@noescape predicate: (Self.Generator.Element) throws -> Bool) rethrows -> Bool 

и подпись containsString:

public func containsString(other: String) -> Bool 

мы можем видеть, что на массив строк параметр predicate и результат String.containsString("The red one.") совместимы: как ожидают String в качестве аргумента и возвращает Bool. Таким образом, компилятор может с радостью назвать функцию curried.

+1

Большая часть вашего ответа выглядит хорошо для меня. Но 'containsString()' - это метод экземпляра, а не глобальная или вложенная функция. –

+0

У вас есть точка ... Я исследовал немного больше и нашел объяснение, почему работают функции экземпляра. Спасибо @MartinR за отзыв – Cristik

+1

Не следует 'String.containsString (« Красный.")' возвращает функцию с сигнатурой '(String) -> Bool' вместо' (String) -> String', поскольку подпись 'containsString' является' public func containsString (other: String) -> Bool'? –