Обобщения
Универсальный код позволяет Вам записать гибкие, допускающие повторное использование функции и типы, которые могут работать с любым типом согласно требованиям, чтобы Вы определили. Можно записать код, избегающий дублирования и выражающий его намерение ясным, абстрактным способом.
Обобщения являются одной из наиболее мощных функций Swift, и большая часть библиотеки стандарта Swift создается с универсальным кодом. Фактически, Вы использовали обобщения всюду по Руководству по Языку, даже если Вы не понимали его. Например, Swift Array
и Dictionary
типы являются оба универсальными наборами. Можно создать содержащий массив Int
содержащий значения или массив String
значения, или действительно массив для любого другого типа, который может быть создан в Swift. Точно так же можно создать словарь для хранения значений любого указанного типа, и нет никаких ограничений на то, каков тот тип может быть.
Проблема, которую решают обобщения
Вот стандарт, вызванная неродовая функция swapTwoInts
, который подкачивает два Int
значения:
func swapTwoInts(inout a: Int, inout b: Int) {
let temporaryA = a
a = b
b = temporaryA
}
Эта функция использует изменяемые параметры для свопинга значений a
и b
, как описано в Изменяемых параметрах.
swapTwoInts
функционируйте подкачивает исходное значение b
в a
, и исходное значение a
в b
. Можно вызвать эту функцию для свопинга значений в два Int
переменные:
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
println("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// prints "someInt is now 107, and anotherInt is now 3"
swapTwoInts
функция полезна, но она может только использоваться с Int
значения. Если Вы хотите подкачать два String
значения, или два Double
значения, необходимо записать больше функций, такой как swapTwoStrings
и swapTwoDoubles
функции, показанные ниже:
func swapTwoStrings(inout a: String, inout b: String) {
let temporaryA = a
a = b
b = temporaryA
}
func swapTwoDoubles(inout a: Double, inout b: Double) {
let temporaryA = a
a = b
b = temporaryA
}
Вы, возможно, заметили что организации swapTwoInts
, swapTwoStrings
, и swapTwoDoubles
функции идентичны. Единственной разницей является тип значений, которые они принимают (Int
, String
, и Double
).
Это было бы намного более полезным, и значительно более гибким, для записи единственной функции, которая могла подкачать два значения любого типа. Универсальный код позволяет Вам записать такую функцию. (Универсальная версия этих функций определяется ниже.)
Родовые функции
Родовые функции могут работать с любым типом. Вот универсальная версия swapTwoInts
функционируйте сверху, вызванные swapTwoValues
:
func swapTwoValues<T>(inout a: T, inout b: T) {
let temporaryA = a
a = b
b = temporaryA
}
Организация swapTwoValues
функция идентична организации swapTwoInts
функция. Однако первая строка swapTwoValues
немного отличается от swapTwoInts
. Вот то, как первые строки выдерживают сравнение:
func swapTwoInts(inout a: Int, inout b: Int)
func swapTwoValues<T>(inout a: T, inout b: T)
Универсальная версия функции использует имя типа заполнителя (вызванный T
, в этом случае) вместо фактического имени типа (такой как Int
, String
, или Double
). Имя типа заполнителя ничего не говорит о какой T
должен быть, но это действительно говорит это оба a
и b
должен иметь тот же тип T
, безотносительно T
представляет. Фактический тип для использования вместо T
будет определен каждый раз swapTwoValues
функция вызвана.
Другое различие то, что имя родовой функции (swapTwoValues
) сопровождается именем типа заполнителя (T
) в угловых скобках (<T>
). Скобки говорят Swift это T
имя типа заполнителя в swapTwoValues
функциональное определение. Поскольку T
заполнитель, Swift не ищет фактический вызванный тип T
.
swapTwoValues
функция может теперь быть вызвана таким же образом как swapTwoInts
, за исключением того, что это может быть передано два значения любого типа, пока оба из тех значений имеют тот же тип друг как друг. Каждый раз swapTwoValues
вызывается, тип для использования для T
выведен из типов значений, переданных функции.
В этих двух примерах ниже, T
выведен, чтобы быть Int
и String
соответственно:
var someInt = 3
var anotherInt = 107
swapTwoValues(&someInt, &anotherInt)
// someInt is now 107, and anotherInt is now 3
var someString = "hello"
var anotherString = "world"
swapTwoValues(&someString, &anotherString)
// someString is now "world", and anotherString is now "hello"
Введите параметры
В swapTwoValues
пример выше, тип заполнителя T
пример параметра типа. Введите параметры, указывают и называют тип заполнителя и сразу записаны после имени функции, между парой соответствия угловых скобок (такой как <T>
).
Как только Вы указываете параметр типа, можно использовать его для определения типа параметров функции (такой как a
и b
параметры swapTwoValues
функция), или как тип возврата функции, или как аннотация типа в организации функции. В каждом случае тип заполнителя, представленный параметром типа, заменяется фактическим типом каждый раз, когда вызвана функция. (В swapTwoValues
пример выше, T
был заменен Int
в первый раз функция была вызвана и была заменена String
во второй раз это вызвали.)
Можно обеспечить больше чем один параметр типа путем записи многократных названий параметра типа в угловых скобках, разделенных запятыми.
Именование параметров типа
В простых случаях, где родовая функция или универсальный тип относятся к единственному типу заполнителя (такой как swapTwoValues
родовая функция выше, или универсальный набор, хранящий единственный тип, такой как Array
), традиционно использовать односимвольное имя T
для параметра типа. Однако можно использовать любой допустимый идентификатор в качестве названия параметра типа.
При определении более сложных родовых функций или универсальных типов с многократными параметрами полезно обеспечить более дескриптивные названия параметра типа. Например, Swift Dictionary
тип имеет два параметра типа — один для его ключей и один для его значений. Если Вы писали Dictionary
самостоятельно, Вы могли бы назвать эти два параметра типа Key
и Value
напомнить Вам об их цели, поскольку Вы используете их в своем универсальном коде.
Универсальные типы
В дополнение к родовым функциям Swift позволяет Вам определить свои собственные универсальные типы. Это пользовательские классы, структуры и перечисления, которые могут работать с любым типом похожим способом к Array
и Dictionary
.
Этот раздел показывает Вам, как записать вызванный тип универсального набора Stack
. Штабель является упорядоченным набором значений, подобных массиву, но с более ограниченным набором операций, чем Swift Array
ввести. Массив позволяет новым элементам быть вставленными и удаленными в любом расположении в массиве. Штабель, однако, позволяет новым элементам быть добавленными только до конца набора (известный как продвижение нового значения на штабеле). Точно так же штабель позволяет элементам быть удаленными только из конца набора (известный как сование значения от штабеля).
Иллюстрация ниже шоу нажатие / выталкивает поведение для штабеля:
На штабеле в настоящее время существует три значения.
Четвертое значение «продвинуто» на вершине штабеля.
Штабель теперь содержит четыре значения с новым наверху.
Главный элемент в штабеле удален или «вытолкан».
После сования значения штабель еще раз содержит три значения.
Вот то, как записать неуниверсальную версию штабеля, в этом случае для штабеля Int
значения:
struct IntStack {
var items = [Int]()
mutating func push(item: Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
}
Эта структура использует Array
свойство вызывают items
сохранить значения в штабеле. Stack
обеспечивает два метода, push
и pop
, продвигать и выталкивать значения на и от штабеля. Эти методы отмечены как mutating
, потому что они должны изменить (или видоизмениться), структура items
массив.
IntStack
введите показанный выше, может только использоваться с Int
значения, как бы то ни было. Было бы намного более полезно определить обобщение Stack
класс, который может управлять штабелем любого типа имеющего значение.
Вот универсальная версия того же кода:
struct Stack<T> {
var items = [T]()
mutating func push(item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
}
Отметьте как универсальная версия Stack
по существу то же как неуниверсальная версия, но с вызванным параметром типа заполнителя T
вместо фактического типа Int
. Этот параметр типа записан в паре угловых скобок (<T>
) сразу после имени структуры.
T
определяет имя заполнителя для “некоторого типа T
” для обеспечения позже. Этот будущий тип может упоминаться как “T
” где угодно в определении структуры. В этом случае, T
используется в качестве заполнителя в трех местах:
Создать вызванное свойство
items
, который инициализируется с пустым массивом значений типаT
Указать что
push(_:)
методу вызвали единственный параметрitem
, который должен иметь типT
Указать что значение, возвращенное
pop()
метод будет значением типаT
Поскольку это - универсальный тип, Stack
может использоваться для создания штабеля любого допустимого типа в Swift, подобным образом к Array
и Dictionary
.
Вы создаете новое Stack
экземпляр путем записи типа, который будет сохранен в штабеле в угловых скобках. Например, для создания нового штабеля строк Вы пишете Stack<String>()
:
var stackOfStrings = Stack<String>()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")
stackOfStrings.push("cuatro")
// the stack now contains 4 strings
Вот то, как stackOfStrings
заботится о продвижении этих четырех значений на штабеле:
Сование значения от штабеля возвращает и удаляет главное значение, "cuatro"
:
let fromTheTop = stackOfStrings.pop()
// fromTheTop is equal to "cuatro", and the stack now contains 3 strings
Вот то, как штабель заботится о совании его главного значения:
Расширение универсального типа
При расширении универсального типа Вы не обеспечиваете список параметров типа как часть определения расширения. Вместо этого список параметров типа из исходного определения типа доступен в организации расширения, и исходные названия параметра типа используются для обращения к параметрам типа из исходного определения.
Следующий пример расширяет обобщение Stack
введите для добавления вычисленного вызванного свойства только для чтения topItem
, который возвращает главный элемент на штабеле, не выталкивая его от штабеля:
extension Stack {
var topItem: T? {
return items.isEmpty ? nil : items[items.count - 1]
}
}
topItem
свойство возвращает дополнительное значение типа T
. Если штабель пуст, topItem
возвраты nil
; если штабель не пуст, topItem
возвращает заключительный элемент в items
массив.
Обратите внимание на то, что это расширение не определяет список параметров типа. Вместо этого Stack
существующее название параметра типа типа, T
, используется в расширении для указания дополнительного типа topItem
вычисленное свойство.
topItem
вычисленное свойство может теперь использоваться с любым Stack
экземпляр, чтобы получить доступ и запросить его главный элемент, не удаляя его:
if let topItem = stackOfStrings.topItem {
println("The top item on the stack is \(topItem).")
}
// prints "The top item on the stack is tres."
Введите ограничения
swapTwoValues
функционируйте и Stack
тип может работать с любым типом. Однако иногда полезно осуществить ограничения определенного типа на типы, которые могут использоваться с родовыми функциями и универсальными типами. Ограничения типа указывают, что параметр типа должен наследоваться от определенного класса, или соответствовать определенному составу протокола или протокола.
Например, Swift Dictionary
введите помещает ограничение на типы, которые могут использоваться в качестве ключей для словаря. Как описано в Словарях, тип ключей словаря должен быть hashable. Т.е. это должно обеспечить способ сделать себя уникально представимым. Dictionary
нуждается в его ключах, чтобы быть hashable так, чтобы это могло проверить, содержит ли это уже значение для определенного ключа. Без этого требования, Dictionary
не мог сказать, должно ли это вставить или заменить значение для определенного ключа, и при этом это не было бы в состоянии найти значение для данного ключа, который уже находится в словаре.
Это требование осуществляется ограничением типа на ключевой тип для Dictionary
, который указывает, что ключевой тип должен соответствовать Hashable
протокол, особый протокол определяется в библиотеке стандарта Swift. Все основные типы Swift (такой как String
, Int
, Double
, и Bool
) hashable по умолчанию.
Можно определить собственные ограничения типа при создании пользовательских универсальных типов, и эти ограничения обеспечивают большую часть питания универсального программирования. Абстрактные понятия как Hashable
охарактеризуйте типы с точки зрения их концептуальных характеристик, а не их явный тип.
Введите ограничительный синтаксис
Вы пишете ограничения типа путем размещения единого класса или ограничения протокола после имени параметра типа, разделенного двоеточием, как часть списка параметров типа. Базовый синтаксис для ограничений типа на родовую функцию показан ниже (несмотря на то, что синтаксис является тем же для универсальных типов):
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
// function body goes here
}
Гипотетическая функция выше имеет два параметра типа. Первый параметр типа, T
, имеет требующее ограничение типа T
быть подклассом SomeClass
. Второй параметр типа, U
, имеет требующее ограничение типа U
соответствовать протоколу SomeProtocol
.
Введите ограничения в действии
Вот вызванная неродовая функция findStringIndex
, которому дают a String
значение для нахождения и массив String
значения, в которых можно найти его. findStringIndex
функционируйте возвращает дополнительное Int
значение, которое будет индексом первой соответствующей строки в массиве, если это будет найдено, или nil
если не может быть найдена строка:
func findStringIndex(array: [String], valueToFind: String) -> Int? {
for (index, value) in enumerate(array) {
if value == valueToFind {
return index
}
}
return nil
}
findStringIndex
функция может использоваться для нахождения строкового значения в массиве строк:
let strings = ["cat", "dog", "llama", "parakeet", "terrapin"]
if let foundIndex = findStringIndex(strings, "llama") {
println("The index of llama is \(foundIndex)")
}
// prints "The index of llama is 2"
Принцип нахождения индекса значения в массиве не полезен только для строк, как бы то ни было. Можно записать ту же функциональность как вызванная родовая функция findIndex
, путем замены любого упоминания о строках со значениями некоторого типа T
вместо этого.
Вот то, как Вы могли бы ожидать универсальную версию findStringIndex
, вызванный findIndex
, быть записанным. Обратите внимание на то, что тип возврата этой функции тих Int?
, потому что функция возвращает дополнительный индекс, не дополнительное значение от массива. Будьте предупреждены, хотя — эта функция не компилирует по причинам, объясненным после примера:
func findIndex<T>(array: [T], valueToFind: T) -> Int? {
for (index, value) in enumerate(array) {
if value == valueToFind {
return index
}
}
return nil
}
Эта функция не компилирует, как записано выше. Проблема связана с проверкой равенства, “if value == valueToFind
”. Не каждый тип в Swift может быть по сравнению с равным оператору (==
). Если Вы создаете свой собственный класс или структуру для представления сложной модели данных, например, то значение “равного” для того класса или структуры не является чем-то, что Swift может предположить для Вас. Из-за этого не возможно гарантировать, что этот код будет работать на каждый возможный тип T
, когда Вы пытаетесь скомпилировать код, и сообщают о надлежащей ошибке.
Не все потеряно, как бы то ни было. Библиотека стандарта Swift определяет вызванный протокол Equatable
, который требует, чтобы любой тип приспосабливания реализовал равное оператору (==
) и не равняются оператору (!=
) сравнить любые два значения того типа. Все стандартные типы Swift автоматически поддерживают Equatable
протокол.
Любой тип, который является Equatable
может использоваться безопасно с findIndex
функция, потому что это, как гарантируют, будет поддерживать равное оператору. Для выражения этого факта Вы пишете ограничение типа Equatable
как часть определения параметра типа, когда Вы определяете функцию:
func findIndex<T: Equatable>(array: [T], valueToFind: T) -> Int? {
for (index, value) in enumerate(array) {
if value == valueToFind {
return index
}
}
return nil
}
Единственный параметр типа для findIndex
записан как T: Equatable
, что означает “любой тип T
это соответствует Equatable
протокол”.
findIndex
функционируйте теперь компилирует успешно и может использоваться с любым типом, который является Equatable
, такой как Double
или String
:
let doubleIndex = findIndex([3.14159, 0.1, 0.25], 9.3)
// doubleIndex is an optional Int with no value, because 9.3 is not in the array
let stringIndex = findIndex(["Mike", "Malcolm", "Andrea"], "Andrea")
// stringIndex is an optional Int containing a value of 2
Связанные типы
При определении протокола иногда полезно объявить один или несколько связанные типы как часть определения протокола. Связанный тип дает имя заполнителя (или псевдоним) к типу, использующемуся в качестве части протокола. Фактический тип для использования для того связанного типа не указан, пока протокол не принят. Связанные типы указаны с typealias
ключевое слово.
Связанные типы в действии
Вот пример вызванного протокола Container
, который объявляет связанный вызванный тип ItemType
:
protocol Container {
typealias ItemType
mutating func append(item: ItemType)
var count: Int { get }
subscript(i: Int) -> ItemType { get }
}
Container
протокол определяет три требуемых возможности, которые должен обеспечить любой контейнер:
Должно быть возможно добавить новый элемент к контейнеру с
append(_:)
метод.Должно быть возможно получить доступ к количеству элементов в контейнере через a
count
свойство, возвращающеесяInt
значение.Должно быть возможно получить каждый элемент в контейнере с нижним индексом, берущим
Int
индексное значение.
Этот протокол не указывает, как элементы в контейнере должны быть сохранены или что вводит, им позволяют быть. Протокол только указывает три бита функциональности, которую любой тип должен обеспечить для рассмотрения a Container
. Соответствующий тип может обеспечить дополнительную функциональность, пока это удовлетворяет эти три требования.
Любой тип, соответствующий Container
протокол должен быть в состоянии указать тип значений, которые это хранит. В частности это должно гарантировать, что только элементы правильного типа добавляются к контейнеру, и это должно согласиться с типом элементов, возвращенных его нижним индексом.
Определить эти требования, Container
для протокола нужен способ относиться к типу элементов, которые контейнер будет содержать, не зная то, что тот тип для определенного контейнера. Container
протокол должен указать, что любое значение передало append(_:)
метод должен иметь тот же тип как тип элемента контейнера, и что значение, возвращенное нижним индексом контейнера, будет иметь тот же тип как тип элемента контейнера.
Достигнуть этого, Container
протокол объявляет связанный вызванный тип ItemType
, записанный как typealias ItemType
. Протокол не определяет что ItemType
псевдоним для — что информация оставлена для любого типа приспосабливания для обеспечения. Тем не менее, ItemType
псевдоним обеспечивает способ относиться к типу элементов в a Container
, и определить тип для использования с append(_:)
метод и нижний индекс, чтобы гарантировать, что ожидаемое поведение любого Container
осуществляется.
Вот версия необобщения IntStack
введите от ранее, адаптированный для приспосабливания Container
протокол:
struct IntStack: Container {
// original IntStack implementation
var items = [Int]()
mutating func push(item: Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
// conformance to the Container protocol
typealias ItemType = Int
mutating func append(item: Int) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Int {
return items[i]
}
}
IntStack
введите реализует все три из Container
требования протокола, и в каждом случае обертывают часть IntStack
существующая функциональность типа для удовлетворения этих требований.
Кроме того, IntStack
указывает это для этой реализации Container
, надлежащее ItemType
использовать - тип Int
. Определение typealias ItemType = Int
поворачивает абстрактный тип ItemType
в конкретный тип Int
для этой реализации Container
протокол.
Благодаря выводу типа Swift Вы не должны фактически объявлять бетон ItemType
из Int
как часть определения IntStack
. Поскольку IntStack
соответствует всем требованиям Container
протокол, Swift может вывести надлежащее ItemType
использовать, просто путем рассмотрения типа append(_:)
метод item
параметр и тип возврата нижнего индекса. Действительно, если Вы удаляете typealias ItemType = Int
строка от кода выше, все все еще работает, потому что ясно, для чего должен использоваться тип ItemType
.
Можно также сделать обобщение Stack
тип соответствует Container
протокол:
struct Stack<T>: Container {
// original Stack<T> implementation
var items = [T]()
mutating func push(item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
// conformance to the Container protocol
mutating func append(item: T) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> T {
return items[i]
}
}
На сей раз, параметр типа заполнителя T
используется в качестве типа append(_:)
метод item
параметр и тип возврата нижнего индекса. Swift может поэтому вывести это T
надлежащий тип для использования в качестве ItemType
для этого определенного контейнера.
Расширение существующего типа для указания связанного типа
Можно расширить существующий тип для добавления соответствия к протоколу, как описано в Добавляющем Соответствии Протокола с Расширением. Это включает протокол со связанным типом.
Swift Array
тип уже обеспечивает append(_:)
метод, a count
свойство и нижний индекс с Int
индекс для получения его элементов. Эти три возможности соответствуют требования Container
протокол. Это означает, что можно расшириться Array
соответствовать Container
протокол просто путем объявления этого Array
принимает протокол. Вы делаете это с пустым расширением, как описано в Объявлении Принятия Протокола с Расширением:
extension Array: Container {}
Существующий массив append(_:)
метод и нижний индекс позволяют Swift вывести надлежащий тип для использования для ItemType
, так же, как для обобщения Stack
введите выше. После определения этого расширения можно использовать любого Array
как a Container
.
Операторы Where
Введите ограничения, как описано в Ограничениях Типа, позвольте Вам определить требования к параметрам типа, связанным с родовой функцией или типом.
Может также быть полезно определить требования для связанных типов. Вы делаете это путем определения где пункты как часть списка параметров типа. Где пункт позволяет Вам потребовать, чтобы связанный тип соответствовал определенному протоколу, и/или что параметры определенного типа и связали типы быть тем же. Вы пишете где пункт путем размещения where
ключевое слово сразу после списка параметров типа, сопровождаемых одним или более ограничениями для связанных типов и/или одним или более отношениями равенства между типами и связанными типами.
Пример ниже определяет вызванную родовую функцию allItemsMatch
, который проверяет, чтобы видеть если два Container
экземпляры содержат те же элементы в том же порядке. Функция возвращает булево значение true
если все элементы соответствуют и значение false
если они не делают.
Эти два контейнера, которые будут проверены, не должны быть тем же типом контейнера (несмотря на то, что они могут быть), но они действительно должны содержать тот же тип элементов. Это требование выражено через комбинацию ограничений типа и где пункты:
func allItemsMatch<
C1: Container, C2: Container
where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
(someContainer: C1, anotherContainer: C2) -> Bool {
// check that both containers contain the same number of items
if someContainer.count != anotherContainer.count {
return false
}
// check each pair of items to see if they are equivalent
for i in 0..<someContainer.count {
if someContainer[i] != anotherContainer[i] {
return false
}
}
// all items match, so return true
return true
}
Эта функция берет два вызванные параметра someContainer
и anotherContainer
. someContainer
параметр имеет тип C1
, и anotherContainer
параметр имеет тип C2
. Оба C1
и C2
параметры типа заполнителя для двух контейнерных типов, которые будут определены, когда вызвана функция.
Список параметров типа функции налагает следующие требования на два параметра типа:
C1
должен соответствоватьContainer
протокол (записанный какC1: Container
).C2
должен также соответствоватьContainer
протокол (записанный какC2: Container
).ItemType
дляC1
должен совпасть сItemType
дляC2
(записанный какC1.ItemType == C2.ItemType
).ItemType
дляC1
должен соответствоватьEquatable
протокол (записанный какC1.ItemType: Equatable
).
Третьи и четвертые требования определяются как часть, где пункт, и записан после where
ключевое слово как часть списка параметров типа функции.
Эти требования среднее значение:
someContainer
контейнер типаC1
.anotherContainer
контейнер типаC2
.someContainer
иanotherContainer
содержите тот же тип элементов.Элементы в
someContainer
может быть сверен не, равняются оператору (!=
) видеть, отличаются ли они друг от друга.
Третьи и четвертые требования объединяются, чтобы означать что элементы в anotherContainer
может также быть сверен !=
оператор, потому что они - точно тот же тип как элементы в someContainer
.
Эти требования включают allItemsMatch
функция для сравнения этих двух контейнеров, даже если они имеют различный контейнерный тип.
allItemsMatch
функция запускается путем проверки, что оба контейнера содержат то же число элементов. Если они содержат различное число элементов, нет никакого способа, которым они могут соответствовать, и функциональные возвраты false
.
После осуществления этой проверки функция выполняет итерации по всем элементам в someContainer
с a for
-in
цикл и полуоткрытый оператор диапазона (..<
). Для каждого элемента функция проверяет ли элемент от someContainer
не равно соответствующему элементу в anotherContainer
. Если эти два элемента не равны, то эти два контейнера не соответствуют, и функциональные возвраты false
.
Если цикл заканчивается, не находя несоответствие, эти два соответствия контейнеров и функциональные возвраты true
.
Вот то, как allItemsMatch
функциональные взгляды в действии:
var stackOfStrings = Stack<String>()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")
var arrayOfStrings = ["uno", "dos", "tres"]
if allItemsMatch(stackOfStrings, arrayOfStrings) {
println("All items match.")
} else {
println("Not all items match.")
}
// prints "All items match."
Пример выше создает a Stack
экземпляр для хранения String
значения и нажатия три строки на штабель. Пример также создает Array
экземпляр, инициализированный с литералом массивов, содержащим те же три строки как штабель. Даже при том, что штабель и массив имеют другой тип, они оба соответствуют Container
протокол, и оба содержат тот же тип значений. Можно поэтому вызвать allItemsMatch
функция с этими двумя контейнерами как ее параметры. В примере выше, allItemsMatch
функционируйте правильно сообщает, что соответствуют все элементы в этих двух контейнерах.