我有一个名为Card
的简单结构......
struct Card {
var order: Int? = -1
var data : [String: String]
var original : String?
一个名为Deck
的集合对象,看起来像......
struct Deck {
var cards : [Card]
Deck有读写方法,它基本上归结为将从文本文件读入的字符串拆分,然后将其一点一点地推入前一个空data
。这是一个例子......
mutating func parseGRCard(var c: Card) {
c.data["I1"] = c.original![2...4].trim()
c.data["I2"] = c.original![5...9].trim()
}
要读取文件,我得到每一行,制作一个Card
,然后调用它上面的解析方法......
let nc = Card(order: i, original: c)
parseGRCard(nc)
cards.append(nc)
当我单步执行此函数时,我看到mc的original
具有预期的数据,即文本文件中的原始行。然后我会看parseGRCard
阅读它并将项目添加到data
,现在有两项。但是当它返回并附加了nc时,data
为空。
我认为mutating
应该处理这些事情,但显然我在这里缺少一些基本的东西。
答案 0 :(得分:1)
我改变了你的代码以使其编译并使其更具说明性。
append
正在变异,因为它会改变cards
。
它的参数c
是一个inout参数,以便在函数之后传递传递的Card
。由于Structs
是值类型而不是引用类型,因此实际将新副本传递给函数。此行为与作为变异函数的函数无关。
struct Card {
var placeInDeck: Int = 0
}
struct Deck {
var cards : [Card] = []
mutating func append(inout c: Card) {
c.placeInDeck = cards.count
cards.append(c)
}
}
var cardZero = Card()
var cardOne = Card()
var deck = Deck()
deck.append(&cardZero)
deck.append(&cardOne)
cardZero.placeInDeck // 0
cardOne.placeInDeck // 1
在这种情况下,函数不会发生变异,因为Deck
的属性没有被更改。 c
参数是一个变量,只是在函数范围内使其可变。 注意,这将从Swift中删除。当函数结束时,Card
的这个可变副本不会更新它在函数范围之外的原始实例。 1}}不会保留更新。
Card
答案 1 :(得分:1)
从Apple's documentation methods开始,我们可以阅读以下有关mutable
关键字的信息:
但是,如果您需要修改结构的属性或 在特定方法中枚举,您可以选择进行变异 该方法的行为。然后方法可以变异(即更改) 方法中的 属性,以及它所做的任何更改 当方法结束时,将写回原始结构。
我同意可以将粗体标记的部分解释为"方法的属性,即它的参数?" 。从您上面的示例中,您似乎已经完成了这种解释。
但是mutable关键字只告诉我们允许关联函数更改(mutate)拥有该方法的struct(在本例中)的变量成员值。
struct SingleIntegerValueStruct1 {
var myInt = 1
func LetsTryToMutateTheInteger () {
myInt += 1 // compile time error; myInt immutable
}
}
然而,如果我们使用mutating关键字
struct SingleIntegerValueStruct {
var myInt = 0
mutating func LetsTryToMutateTheInteger () {
myInt += 1 // ok, mutating function
}
}
var a = SingleIntegerValueStruct(myInt: 1)
print("\(a.myInt)") // 1
a.LetsTryToMutateTheInteger()
print("\(a.myInt)") // 2
但是,struct
类型始终是值类型。因此,当struct
类型传递给任何函数时,该函数将无法改变调用者参数,因为它只给出了它的副本。
let nc = Card(order: i, original: c)
parseGRCard(nc) // passes _copy_ of struct typ nc to parseGRCard
cards.append(nc) // nc in this scope is stil unchanged
如果想要使用可能改变其输入参数的"独立" 函数,输入是结构,您可以,如评论中所述,我们函数参数的inout
关键字。
我们从上面扩展我们的例子,包括这样一个案例:
struct SingleIntegerValueStruct {
var myInt = 0
mutating func LetsTryToMutateTheInteger () {
myInt += 1 // ok, mutating function
}
}
// "b" here is a _copy_ of "a" (in parameter), and the function
// thereafter returns a _copy_ of "b" (with state of "b" as its
// final state in the function)
func standAloneInOutFunction(inout b: SingleIntegerValueStruct) {
b.LetsTryToMutateTheInteger()
}
var a = SingleIntegerValueStruct(myInt: 1)
print("\(a.myInt)") // 1
a.LetsTryToMutateTheInteger()
print("\(a.myInt)") // 2
standAloneInOutFunction(&a)
// value copy a->b, modify(b), value copy back b->a
print("\(a.myInt)") // 3
但是请注意,inout
关键字并不意味着我们通过引用(就像类实例一样),但我们只是发送一个值副本并将另一个值复制回来,我们最终分配给原始值类型调用参数(a)。
来自Apple documentation on this keyword:
...输入输出参数具有传递给函数的值, 由函数修改,并从函数传递回去 替换原始值。