Swift元组 - 与struct和彼此不同?

时间:2021-07-09 14:01:20

How different are tuples in swift from structures? (1)

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

As I understand, both tuples and structures can be sent by value instead by reference in function calls, returns, right?

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

Also, I know that if have

另外,我知道如果有的话

var A : StructureX
var B : StructureX

I know that structure A and B have the same Type, which is StructureX. But...

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

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

Are A and B tuples the same Type? (2) What are the advantages about using Tuples instead of structures? (3)

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

2 个解决方案

#1


17  

I find it's easiest to conceptualize Swift Tuples as "Anonymous Structs" with a few critical differences. They behave similarly, but a struct has a formal definition and allows more control over mutability, while tuples allow for pattern matching.

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

Similarities Between Tuples and Structs

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

  • Both may have any number of members of any type, including closures
  • 两者都可以包含任何类型的任意数量的成员,包括闭包
  • Both can be constructed inline (see typealias in the code below)
  • 两者都可以内联构造(请参阅下面代码中的typealias)
  • Both prevent mutation of any members if declared as constants
  • 如果声明为常量,两者都可以防止任何成员的突变
  • If a tuple has labeled members, both structs and tuples allow member access by label
  • 如果元组具有标记成员,则结构和元组都允许通过标签访问成员

Differences Between Tuples and Structs

元组和结构之间的差异

  • Structs require a definition before use
  • 结构在使用前需要定义
  • Structs do not allow pattern matching against their members
  • 结构不允许对其成员进行模式匹配
  • Structs allow mutability of members declared as variables if the instance is a variable
  • 如果实例是变量,则结构允许声明为变量的成员的可变性
  • Tuples do not allow mutating functions or functions that refer to any of its members
  • 元组不允许改变引用其任何成员的函数或函数
  • Tuples may not implement Protocols
  • 元组可能不会实现协议
  • If a tuple has anonymous members, its members can be accessed by index, unlike structs
  • 如果元组具有匿名成员,则可以通过索引访问其成员,这与结构不同

Some code for a playground illustrating these differences and similarities

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

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

#2


5  

I'm not sure the official terminology around tuples however, you declare them as if they were a special kind of type:

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

let A : (Int, String)

Maybe we could say that A is now a variable of type tuple? However, not all tuples are the same. If you declare variable of type tuple and try to assign it a tuple with parameters that differ in count, sequence, or type you'll get a compiler error. This will fail

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

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

Though this works fine:

虽然这很好:

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

Of course this strong type safety is also enforced with structs.

当然,这种强大的类型安全性也可以用结构来强制执行。

As far as the advantages, here are some thoughts on the differences I'm aware of.

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

Structures require that you define them before using them. Tuples, on the other hand, let you return an arbitrary list of values. How is this useful? I have an iPad app with a shopping cart view controller in it. There is a summary view in the cart view that displays a current status of what's in the cart at any given time--sometimes just normal items, but RMA items and items on re-order are also potentially in the cart. I have a method on my shopping cart class that returns a tuple containing cart count, RMA count, re-order count, and total count. I don't have to declare a structure to get back all four values. It's very convenient:

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

In my cart view:

在我的购物车视图中:

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

There may be other reasons, but convenience is the most compelling one for me to prefer tuples in this scenario.

可能还有其他原因,但在这种情况下,方便性对我来说是最有吸引力的。

#1


17  

I find it's easiest to conceptualize Swift Tuples as "Anonymous Structs" with a few critical differences. They behave similarly, but a struct has a formal definition and allows more control over mutability, while tuples allow for pattern matching.

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

Similarities Between Tuples and Structs

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

  • Both may have any number of members of any type, including closures
  • 两者都可以包含任何类型的任意数量的成员,包括闭包
  • Both can be constructed inline (see typealias in the code below)
  • 两者都可以内联构造(请参阅下面代码中的typealias)
  • Both prevent mutation of any members if declared as constants
  • 如果声明为常量,两者都可以防止任何成员的突变
  • If a tuple has labeled members, both structs and tuples allow member access by label
  • 如果元组具有标记成员,则结构和元组都允许通过标签访问成员

Differences Between Tuples and Structs

元组和结构之间的差异

  • Structs require a definition before use
  • 结构在使用前需要定义
  • Structs do not allow pattern matching against their members
  • 结构不允许对其成员进行模式匹配
  • Structs allow mutability of members declared as variables if the instance is a variable
  • 如果实例是变量,则结构允许声明为变量的成员的可变性
  • Tuples do not allow mutating functions or functions that refer to any of its members
  • 元组不允许改变引用其任何成员的函数或函数
  • Tuples may not implement Protocols
  • 元组可能不会实现协议
  • If a tuple has anonymous members, its members can be accessed by index, unlike structs
  • 如果元组具有匿名成员,则可以通过索引访问其成员,这与结构不同

Some code for a playground illustrating these differences and similarities

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

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

#2


5  

I'm not sure the official terminology around tuples however, you declare them as if they were a special kind of type:

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

let A : (Int, String)

Maybe we could say that A is now a variable of type tuple? However, not all tuples are the same. If you declare variable of type tuple and try to assign it a tuple with parameters that differ in count, sequence, or type you'll get a compiler error. This will fail

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

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

Though this works fine:

虽然这很好:

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

Of course this strong type safety is also enforced with structs.

当然,这种强大的类型安全性也可以用结构来强制执行。

As far as the advantages, here are some thoughts on the differences I'm aware of.

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

Structures require that you define them before using them. Tuples, on the other hand, let you return an arbitrary list of values. How is this useful? I have an iPad app with a shopping cart view controller in it. There is a summary view in the cart view that displays a current status of what's in the cart at any given time--sometimes just normal items, but RMA items and items on re-order are also potentially in the cart. I have a method on my shopping cart class that returns a tuple containing cart count, RMA count, re-order count, and total count. I don't have to declare a structure to get back all four values. It's very convenient:

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

In my cart view:

在我的购物车视图中:

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

There may be other reasons, but convenience is the most compelling one for me to prefer tuples in this scenario.

可能还有其他原因,但在这种情况下,方便性对我来说是最有吸引力的。