2015-07-18 210 views
11

我已经看过类似的问题,但我还没有看到我满意的答案。Swift通过引用传递结构?

以引用的方式传递结构是可能的还是可取的?如果是这样如何?

这里是一个代码,作为实例的引用:

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

正如你看到我这样做的主要原因是因为没有我的形象所有的地方繁殖。

+1

幸运的是,你的图像是一个引用类型,并且你将通过传递对UIImage的引用来传递结构的值相同。 –

+0

这将是一个很好的答案与来源 – Esqarrouth

回答

31

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

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

请注意,这样做不会节省复制UIImage的负担。当你把一个引用类型作为一个结构体的成员时,你仍然只是在你传值的时候复制引用。您不复制图像的内容。

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

查看WWDC video on value types了解更多。

3

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

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

另外的编译器优化代码,以便结构得到内部通过引用传递和复制如果需要的话。

正如在顶级代码引用传递一个结构的一个例子,你可以使用inout参数: 因此,一个inout参数可以通过引用传递,但斯威夫特的实施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 

正如你可以看到myTestt仅在情况下1当量(“真”参考语义) 。因此,如果您在函数本身中也引用了myTest,这会产生巨大的差异。但只要你不这样做,你就很好。