Ответ 1
Мне легче всего концептуализировать Swift Tuples как "анонимные структуры" с несколькими критическими различиями. Они ведут себя аналогично, но структура имеет формальное определение и позволяет больше контролировать изменчивость, в то время как кортежи позволяют сопоставлять шаблоны.
Сходства между кортежами и структурами
- Оба могут иметь любое количество членов любого типа, включая замыкания
- Оба могут быть построены inline (см.
typealias
в коде ниже) - Оба предотвращают мутацию любых членов, если они объявлены как константы.
- Если кортеж имеет помеченные члены, обе структуры и кортежи допускают доступ членов с помощью метки
Различия между кортежами и структурами
- Структуры требуют определения перед использованием
- Структуры не позволяют сопоставлять шаблоны с их членами.
- Структуры допускают изменчивость членов, объявленных как переменные, если экземпляр является переменной
- Кортежи не позволяют изменять функции или функции, относящиеся к любому из его членов.
- Кортежи могут не выполнять протоколы
- Если кортеж имеет анонимных членов, к его членам можно получить доступ по индексу, в отличие от structs
Некоторый код для игровой площадки, иллюстрирующий эти различия и сходства
// All commented code causes a compilation error. Uncomment to view error messages.
struct StructureX {
let a: Int = 0
var b: String = "string"
}
//
// Struct member variability
//
var structureA: StructureX = StructureX()
let structureB: StructureX = StructureX()
//structureA.a = 2 // declared as a constant, instance is variable
structureA.b = "allowed" // declared as a variable, instance is variable
//structureB.a = 2 // declared as constant, instance is constant
//structureB.b = "not allowed" // declared as constant, instance is constant
structureA = structureB // these are the same type
structureA
//
// Typealias a labeled tuple and it can be constructed similarly to a struct
//
typealias StructureT = (a: Int, b: String)
var structureD: StructureT = StructureT(a: 0, b: "asdf")
structureD
//structureD = structureA // but they are distinct types
let emptyTuple: () = () // philosophically, isn't this the definition of Void?
let single: (Int) = (23)
//let namedSingle: (a: Int) = (a: 42)
//
// Tuple Labeled Member Access
//
var labeledTupleA: (a: Int, b: String) = (a: 0, b: "string")
labeledTupleA.0 = 5
labeledTupleA.a
labeledTupleA
var check: (a: Int, b: String)
check = labeledTupleA // same type
check
//
// Tuples can have functions/closures
//
let labeledTupleB: (Int, String, fun: () -> Void) = (0, "string", { () -> Void in
println("hi")
})
labeledTupleB.1
labeledTupleB.fun()
//labeledTupleB.0 = 10 // this tuple is a constant, so all of its members are constant
//
// Tuples with members of the same type, but differet labels are not of the same type
//
var labeledTupleC: (c: Int, d: String) = (c: -1, d: "fail")
//labeledTupleC = labeledTupleA
//labeledTupleC = labeledTupleB
//
// Tuples with anonymous members matching the type pattern of a labeled member tuple are of equivalent type
//
var unlabeledTuple: (Int, String) = (0, "good")
unlabeledTuple = labeledTupleA
unlabeledTuple = labeledTupleC
//
// Tuples with closures may not refer to sibling members
//
var labeledTupleD: (de: Int, df: (Int) -> Void) = (de: 0, df: { (num: Int) -> Void in
//de += num
//self.de += num
println(num)
})
labeledTupleD.de
labeledTupleD.df(1)
//
// Tuples allow pattern matching, Structs do not
//
//switch structureA {
//case (let i, let s):
// print(i, s)
//default:
// break
//}
switch labeledTupleD {
case (_, let closure):
closure(123)
default:
break
}