0

如果我在 XCode 12 Playground (Swift 5.3) 中运行以下代码,我会从两个列表中得到相同的结果:

import Foundation

var dict = NSMutableDictionary()

dict["x"] = 42

func stuff(_ d: inout NSMutableDictionary) {
    d["x"] = 75
}

stuff(&dict)

dump(dict) // x is 75

另一个:

import Foundation

var dict = NSMutableDictionary()

dict["x"] = 42

func stuff(_ d: NSMutableDictionary) {
    d["x"] = 75
}

stuff(dict)

dump(dict) // x is 75 still

根据此处的文档,第二个清单应该给我一个错误: https ://docs.swift.org/swift-book/LanguageGuide/Functions.html

但无论如何它都有效。

这是因为这些进出规则的执行仅限于 Swift 类型,而 Cocoa 类型是例外的吗?

4

1 回答 1

1

这不是因为 Cocoa 类型是豁免的,而是因为NSMutableDictionary是 a class(而不是 a struct),并且 theinout并不代表您可能在想什么。

不幸的是,您链接到的文档(以及有关链接到的参数的更深入的文档inout)并没有清楚地说明“价值”的真正含义:

一个in-out参数有一个值,传入函数,被函数修改,传回函数外替换原来的值

以下语句暗示了一点,但可能更清楚:

您只能将变量作为输入输出参数的参数传递。您不能将常量或文字值作为参数传递,因为无法修改常量和文字。

文档描述的“值”是作为inout. 对于值类型 ( structs),这是有意义的,因为每个持有这些类型值的变量都有效地持有该值的副本

var a = MyGreatStruct(...)
var b = a
// a and b are not directly linked in any way

将 a传递struct给函数通常会将值复制到新的局部变量中(新变量 = 副本),而您可以想象inout让您直接访问原始变量(没有新变量)。

没有描述的是,对于行为不同的类,效果是相同的。

let a = MyGreatClass(...)
let b = a
// modifying `a` will modify `b` too since both point to the same instance

将 a传递class给函数也会将该变量复制到一个新的局部变量中,但该副本没有意义——两个变量都持有相同的东西:对内存中对象本身的引用。从这个意义上说,复制并没有做任何特别的事情,您可以从函数内部修改对象,就像从外部修改对象一样。inoutfor classes 的行为方式与 for structs 相同:它通过引用传递原始变量。这与您想要对对象执行的大多数操作无关(尽管它确实允许您使变量指向函数内的不同对象):

var a = MyGreatClass("Foo")

// func foo(_ value: MyGreatClass) {
//     value = MyGreatClass("Bar") // <- not allowed since `value` isn't mutable
// }

func foo(_ value: inout MyGreatClass) {
    value = MyGreatClass("Bar")
}

print(ObjectIdentifier(a)) // <some pointer>
foo(&a)
print(ObjectIdentifier(a)) // <some other pointer>
于 2020-10-26T22:04:24.780 回答