Tuple vs Struct в Swift

Я понимаю, что кортежи Swift служат, например, как простой способ для функции вернуть несколько значений. Однако, помимо этого "аспекта простоты", я не вижу очень никакой необходимости использовать кортежи вместо структур.

Поэтому мой вопрос: с точки зрения дизайна, есть ли какой-либо сценарий, где кортежи, безусловно, являются лучшим выбором, чем структуры?

Ответ 1

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


Родное Равномерное соответствие для кортежей ограниченного размера

В Swift 2.2 кортежи размером до 6 будут естественным образом равными, учитывая, что члены являются равномерными

Это означает, что кортежи иногда будут естественным выбором при использовании небольших конструкций в ограниченном объеме.

например. рассмотрим следующий пример, используя (1): структуру

struct Foo {
    var a : Int = 1
    var b : Double = 2.0
    var c : String = "3"
}

var a = Foo()
var b = Foo()

// a == b // error, Foo not Equatable

/* we can naturally fix this by conforming Foo to Equatable,
   but this needs a custom fix and is not as versatile as just 
   using a tuple instead. For some situations, the latter will
   suffice, and is to prefer.                                  */
func == (lhs: Foo, rhs: Foo) -> Bool {
    return lhs.a == rhs.a && lhs.b == rhs.b && lhs.c == rhs.c
}

и (2): кортеж

/* This will be native in Swift 2.2 */
@warn_unused_result
public func == <A: Equatable, B: Equatable, C: Equatable>(lhs: (A,B,C), rhs: (A,B,C)) -> Bool {
    return lhs.0 == rhs.0 && lhs.1 == rhs.1 && lhs.2 == rhs.2
}
/* end of native part ...           */

var aa = (1, 2.0, "3")
var bb = (1, 2.0, "3")

aa == bb // true
aa.0 = 2
aa == bb // false

Общий доступ к различным типам кортежей: более универсальный, чем для структур разных типов

Из вышесказанного (сравните функции ==) также очевидно, что кортежи легко работать в контексте дженериков, так как мы можем получить доступ к их анонимным свойствам-членам с помощью .0, .1... суффиксы; тогда как для структуры самый простой способ имитировать это поведение быстро становится довольно сложным, требующим таких инструментов, как интроспекция времени выполнения и т.д., см. например. это.

Ответ 2

Рассмотрим это, java - objective-C. Когда вы должны подключиться к этому типу источника данных в своем проекте (потому что у вас есть огромный базовый код в андроиде и вы не хотите или не можете делать все с нуля), вы обнаруживаете, что с помощью java-типа datasource (например, hashmap) это в основном typedef из objective-c типов. Это не легко подключаться быстро, в зависимости от того, что у вас есть, если вы хотите иметь хороший массив для вашего коллективного просмотра, массив наборов, который будет заполнен java-источником данных, может быть приятным. Небольшой пример кода, чтобы проиллюстрировать это:

var myJavaVar = JavaUtilLinkedHashMap()
var headerArray : [(varName : String, param : Int, varId : jlong)] = []


myJavaVar = myStaticMethodToGetMyVar

    //  get var array
    let keySetJava = myJavaVar.keySet().toArray()
    for jCounter in 0..<Int(myJavaVar.size()){
        // id for index
        let key : Int = keySetJava.objectAtIndex(UInt(jCounter)) as! Int
        let varId = jlong.init(key)
        let varName = myMethodToGetName(varId)
        let myParam : Int = myJavaVar.getWithId(keySetJava.objectAtIndex(UInt(jCounter))) as! Int
        // append data to the array
        headerArray.append((varName: categoryName, param : myParam,duration: duration, varId: varId))
    }

Затем вы можете получить свои данные следующим образом (в методе collectionview):

 let time = headerArray[indexPath.section].param