ios Swift 通过引用传递结构?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31495431/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 06:55:35  来源:igfitidea点击:

Swift pass struct by reference?

iosswiftstruct

提问by Esqarrouth

I've looked to similar questions but I haven't seen an answer that I am satisfied with.

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

Is it possible or advisable to pass structs by reference? If so how?

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

Here is a code as a reference for examples:

这是一个代码作为示例的参考:

struct MyData {
    var contentId: Int = 0
    var authorId: Int = 0
    var image: UIImage = UIImage(named: "myimage")
}

As you see my main reason of doing this is because not having my image multiplying all over the place.

正如你所看到的,我这样做的主要原因是因为我的形象没有到处成倍增加。

回答by Rikki Gibson

Structs can be passed by reference using the inoutkeyword and the &operator.

可以使用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

This practice is discouraged unless you can prove it's the only way to get the performance you need in a critical situation.

不鼓励这种做法,除非您能证明这是在危急情况下获得所需性能的唯一方法。

Note that you won't save the burden of copying the UIImage by doing this. When you put a reference type as a member of a struct, you still only copy the reference when you pass it by value. You are not copying the contents of the image.

请注意,这样做不会减轻复制 UIImage 的负担。当您将引用类型作为结构的成员时,您仍然只在按值传递引用时复制引用。您不是在复制图像的内容。

Another important thing to know about struct performance is copy-on-write. Many built in types like Array are value types, and yet they're very performant. When you pass around a struct in Swift, you don't undergo the burden of copying it until you mutate it.

关于 struct 性能的另一个重要信息是copy-on-write。许多内置类型(如 Array)都是值类型,但它们的性能非常好。当你在 Swift 中传递一个结构体时,你不会承担复制它的负担,直到你改变它。

Check out the WWDC video on value typesto learn more.

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

回答by Qbyte

First of all, if you pass a struct it gets normally passed by value. Even though all properties of the struct get copied only the pointer to properties which are reference types like UIImage gets duplicated (only 8 bytes):

首先,如果你传递一个结构体,它通常是按值传递的。即使结构的所有属性都被复制,只有指向像 UIImage 这样的引用类型的属性的指针被复制(只有 8 个字节):

var data1 = MyData()
var data2 = data1
// both data1 and data2 point to the same image

Also the compiler optimizes the code so structs get internally passed by reference and copied if needed.

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

As an example of passing a struct by reference in top level code you can use inoutparameters: So an inoutparameter can be passed by reference but Swift's general way of implementing inoutis that the parameter gets passes by value and after the function returns it gets reassigned.

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

Although the compiler optimizes the function call so you could get a true reference in some situations. This optimization only affects variables which aren't computed or have a property observer like willSetand didSet(and probably other cases).

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

So you should only rely on the current instance which is not in the scope of the function:

所以你应该只依赖不在函数范围内的当前实例:

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

As you can see myTestand tare only equivalent in case 1 ("true" reference semantics). So this makes a huge difference if you also reference myTestin the function itself. But as long as you don't do this you are good to go.

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