Подтвердить что ты не робот

Swift Suples - отличается от структуры и друг от друга?

Насколько отличаются кортежи в быстром от структуры? (1)

Как я понимаю, оба кортежа и структуры могут быть отправлены значением вместо ссылки на вызовы функций, возвращает, правильно?

Кроме того, я знаю, что если

var A : StructureX
var B : StructureX

Я знаю, что структура A и B имеет тот же Type, который равен StructureX. Но...

let A : (Int, String)
let B : (Int, String)

Являются ли A и B одним и тем же Type? (2) В чем преимущества использования кортежей вместо структур? (3)

4b9b3361

Ответ 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 }

Ответ 2

Я не уверен, что официальная терминология вокруг кортежей, однако, вы объявляете их, как если бы они были особым типом:

let A : (Int, String)

Может быть, мы могли бы сказать, что A теперь является переменной типа tuple? Однако не все кортежи одинаковы. Если вы объявляете переменную типа кортежа и пытаетесь присвоить ей кортеж с параметрами, которые отличаются по количеству, последовательности или типу, вы получите ошибку компилятора. Это не сработает

let A : (Int, String) = ("Bob", 1234, 4.0) 

Хотя это прекрасно работает:

let A : (Int, String) = (1234, "Bob")

Конечно, безопасность этого сильного типа также обеспечивается с помощью структур.

Что касается преимуществ, вот некоторые мысли о различиях, о которых я знаю.

Структуры требуют, чтобы вы определяли их перед их использованием. С другой стороны, кортежи позволяют возвращать произвольный список значений. Как это полезно? У меня есть приложение iPad с контроллером просмотра корзины покупок. В представлении корзины есть сводный вид, который отображает текущий статус того, что в тележке в любой момент времени - иногда просто обычные предметы, но элементы RMA и предметы при повторном заказе также потенциально находятся в корзине. У меня есть метод в классе корзины покупок, который возвращает кортеж, содержащий счетчик корзины, счет RMA, счет повторного заказа и общий счет. Мне не нужно объявлять структуру, чтобы вернуть все четыре значения. Это очень удобно:

class Cart : NSManagedObject {
    ...
    var totals : (cartCount:Int, rmaCount:Int, reorderedCount:Int, totalCount:Int) {
        let cart = ...    // Calculate cart count
        let rma = ...     // Calculate rma count
        let reorder = ... // Calculate reorder count
        let total = cart + rma + reorder // Add them all up

        return (cart, rma, reorder, total)
    }
}

В корзине:

let cartValues = cart.totals
self.summaryView.cartCountLabel.text = "\(cartValues.cartCount)"       
self.summaryView.rmaCountLabel.text = "\(cartValues.rmaCount)"    
self.summaryView.reorderCountLabel.text = "\(cartValues.reorderedCount)"    
self.summaryView.totalCountLabel.text = "\(cartValues.totalCount)"

Могут быть и другие причины, но удобство является наиболее привлекательным для меня, чтобы предпочесть кортежи в этом сценарии.