Swift Tuples - 与struct和彼此不同?

时间:2014-12-09 16:40:33

标签: swift tuples

快速结构中的元组有多么不同? (1)

据我所知,元组和结构都可以通过值发送,而不是通过函数调用中的引用发送,返回,对吧?

另外,我知道如果有

var A : StructureX
var B : StructureX

我知道结构A和B具有相同的Type,即StructureX。但...

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

A和B元组是否相同Type? (2) 使用元组而不是结构有什么好处? (3)

2 个答案:

答案 0 :(得分:19)

我发现将Swift Tuples概念化为“#匿名结构”#34;有一些关键的差异。它们的行为类似,但结构具有正式定义,允许更多地控制可变性,而元组允许模式匹配。

元组和结构之间的相似性

  • 两者都可以包含任意类型的任意数量的成员,包括闭包
  • 两者都可以内联构建(请参阅下面的代码中的typealias
  • 如果声明为常量
  • ,两者都可以防止任何成员的突变
  • 如果元组具有标记成员,则结构和元组都允许成员通过标签访问

元组和结构之间的差异

  • 结构在使用前需要定义
  • 结构不允许对其成员进行模式匹配
  • 如果实例是变量
  • ,则结构允许声明为变量的成员的可变性
  • 元组不允许改变引用其任何成员的函数或函数
  • 元组可能无法实现协议
  • 如果元组具有匿名成员,则可以通过索引访问其成员,而不像结构

游乐场的一些代码,说明了这些差异和相似之处

// 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


//
// A tuple can't be used as a literal to construct a struct.
//
//let StructureC: StructureX = (a: 17, b: "nope")


//
// 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?
print(emptyTuple)               // prints as ()
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
    print("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
    print(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
}

答案 1 :(得分:6)

我不确定元组周围的官方术语,但是你声明它们好像是一种特殊的类型:

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)"

可能还有其他原因,但在这种情况下,方便是我最喜欢的元组。