Swift通过引用传递结构?

Esq*_*uth 16 struct ios swift

我看过类似的问题,但我没有看到我满意的答案.

是否可以或建议通过引用传递结构?如果是这样的话?

以下是代码作为示例的参考:

struct MyData {
    var contentId: Int = 0
    var authorId: Int = 0
    var image: UIImage = UIImage(named: "myimage")
}
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,我这样做的主要原因是因为没有让我的图像遍布整个地方.

Rik*_*son 40

可以使用inout关键字和&运算符通过引用传递结构.

struct Test {
    var val1:Int
    let val2:String

    init(v1: Int, v2: String) {
        val1 = v1
        val2 = v2
    }
}

var myTest = Test(v1: 42, v2: "fred")

func change(test: inout Test) {
    // you can mutate "var" members of the struct
    test.val1 = 24

    // or replace the struct entirely
    test = Test(v1: 10, v2: "joe")
}
change(test: &myTest)
myTest // shows val1=10, val2=joe in the playground
Run Code Online (Sandbox Code Playgroud)

除非您能证明这是在紧急情况下获得所需性能的唯一途径,否则不鼓励这种做法.

请注意,这样做不会节省复制UIImage的负担.将引用类型作为结构的成员放置时,仍然只能在按值传递时复制引用.您没有复制图像的内容.

关于struct性能的另一个重要事项是copy-on-write.像Array这样的许多内置类型都是值类型,但它们非常高效.当你在Swift中传递一个结构时,你不会承担复制它的负担,直到你改变它.

查看有关值类型WWDC视频以了解更多信息.

  • 请注意,这不是通过引用传递。[`inout`](https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#ID545) 关键字在传入值时创建值的副本,然后用副本替换原始值当返回值时。通过引用传递不会涉及复制。 (3认同)

Qby*_*yte 5

首先,如果传递结构,则通常按值传递。即使该结构的所有属性都仅被复制了指向诸如UIImage之类的引用类型的属性的指针,也被重复了(仅8个字节):

var data1 = MyData()
var data2 = data1
// both data1 and data2 point to the same image
Run Code Online (Sandbox Code Playgroud)

此外,编译器还会优化代码,以便结构在内部通过引用传递并在需要时进行复制。

作为在顶级代码中按引用传递结构的示例,您可以使用inout参数:因此,inout可以按引用传递参数,但是Swift的一般实现方式inout是按值传递参数,并在函数返回后对其进行重新分配。

尽管编译器优化了函数调用,但在某些情况下仍可以得到真正的引用。此优化仅影响未计算的变量或具有诸如willSetdidSet(可能还有其他情况)的属性观察器的变量。

因此,您应该仅依赖当前实例,该实例不在函数范围之内:

struct Test {
    var value = 0
}

// case 1
var myTest = Test()

// case 2
var myTest = Test() {
didSet { print("I was set") }
}

// case 3
var myTest: Test {
get{ return Test() }
set{ print("I set myself") }
}

func mutateTest(inout t: Test) {
    // directly referencing to myTest

    myTest.value // value = 0 in all cases

    t.value = 42
    myTest.value // value = 42 in case 1 ; value = 0 in case 2 and 3

    t = Test()   // nothing gets printed
    myTest.value // value = 0 in all cases

    t = Test()   // nothing gets printed
    t.value = 3  // value = 3 in case 1 ; value = 0 in case 2 and 3
}

changeTest(&myTest)
//case 2: "I was set", case 3 "I set myself" get printed now

myTest.value // value = 3 in all cases
Run Code Online (Sandbox Code Playgroud)

如您所见myTestt并且仅在情况1中等效(“ true”参考语义)。因此,如果您还引用myTest函数本身,则将产生巨大的差异。但是,只要您不这样做,就可以继续前进。