Swift Tuples - 与struct和彼此不同?

rod*_*ogq 17 tuples swift

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

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

另外,我知道如果有的话

var A : StructureX
var B : StructureX
Run Code Online (Sandbox Code Playgroud)

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

let A : (Int, String)
let B : (Int, String)
Run Code Online (Sandbox Code Playgroud)

A和B元组是一样的Type吗?(2)使用元组而不是结构有什么好处?(3)

Ral*_*nso 20

我发现将Swift Tuples概念化为"Anonymous Structs"是最容易的,但有一些关键的区别.它们的行为类似,但结构具有正式定义并允许更多地控制可变性,而元组允许模式匹配.

元组与结构之间的相似之处

  • 两者都可以包含任何类型的任意数量的成员,包括闭包
  • 两者都可以内联构建(参见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
}
Run Code Online (Sandbox Code Playgroud)


Mat*_*ong 6

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

let A : (Int, String)
Run Code Online (Sandbox Code Playgroud)

也许我们可以说A现在是元组类型的变量?但是,并非所有元组都是相同的.如果声明类型为tuple的变量并尝试为其分配一个参数在计数,序列或类型上不同的元组,则会出现编译器错误.这将失败

let A : (Int, String) = ("Bob", 1234, 4.0) 
Run Code Online (Sandbox Code Playgroud)

虽然这很好:

let A : (Int, String) = (1234, "Bob")
Run Code Online (Sandbox Code Playgroud)

当然,这种强大的类型安全性也适用于结构.

至于优点,这里有一些关于我所知道的差异的想法.

结构要求您在使用它们之前定义它们.另一方面,元组允许您返回任意值列表.这有用吗?我有一个带有购物车视图控制器的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)
    }
}
Run Code Online (Sandbox Code Playgroud)

在我的购物车视图中:

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)"
Run Code Online (Sandbox Code Playgroud)

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