这个计算属性在当前 Swift 中像“指针”一样工作是否完全正确?

问题描述 投票:0回答:1

有一个数据源单例

class hugestuff ..{

   var dataSources: [String: ThingWithIncrediblyLargeArrays] ..

   var currentThing: String

}

ThingWithIncrediblyLargeArrays
确实是
struct
。典型的用途可能是在屏幕上的网格中显示巨大的值表。每个
ThingWithIncrediblyLargeArrays
- 也就是说
.dataSources
字典中的每个条目 - 可能是不同的屏幕。

struct ThingWithIncrediblyLargeArrays {
   var rawUnsorted: [[String]]
   var liveSorted: [[String]]
   var swapValues: [[String]]
}

因此,在整个应用程序中,您都在访问

  cell.data = hugestuff.dataSources[currentThing].unsortedRows[3489412]

等等。

确实有时会改变事情......

  hugestuff.dataSources[currentThing].searchRows =
       hugestuff.dataSources[currentThing].unsortedRows.filter{blah}

这一切都太棒了,但是纯粹是糖如果

会更方便、更坚固
  cell.data = hugestuff.hot.unsortedRows[3489412]

  hugestuff.hot.searchRows = hugestuff.hot.unsortedRows.filter{blah}

现在,我相信要实现这一目标,如果你这样做

var hot: ThingWithIncrediblyLargeArrays {
    get { dataSources[currentThing] }
    set { dataSources[currentThing] = newValue }
}

一切正常。

换句话说,在这种情况下,使用 Swift 中的字典来执行“类似指针或宏的事情”的方法如上所述。

事实上,这是否能按照预期的方式安全、正确地发挥作用?也就是说,

(一)

x = hugestuff.hot.enormousArray[13]

不会在此过程中无意义地复制数组并且

(B)

hugestuff.hot.searchRows = .. some new or modified array

确实会“实际更改”该数组,即,它不会只是错误地更改数组某处的某些临时副本。

重复一下,在(B)中,

hugestuff.hot.searchRows = hugestuff.hot.other.sortwhatever

希望能和

一样
hugestuff.dataSources["electrons"].searchRows = 
   hugestuff.dataSources["electrons"].other.sortwhatever

换句话说,我希望

hugestuff.hot.searchRows = ..
事实上真的会改变
hugestuff.dataSources["electrons"]

这完全正确吗?

我提到“当前”Swift,当然是因为,Swift 在某一点上极大地改变了数组的工作方式,并且 Swift 使用了巧妙的 (“但是在尝试任何棘手的事情之前先询问一下”) 仅按需复制大数组(或实际上任何数组)的方法。


顺便说一句,这里是对相关问题的非常有用的答案Swift > 绝对不会吗< deep copy a large array, when one "guard let" the array?

dictionary pass-by-reference swift5 computed-properties
1个回答
0
投票

如果

ThingWithIncrediblyLargeArrays
是一个类,则
hot
将简单地充当“指针”。毕竟,类是 reference 类型,并且
hot
将返回引用。

从现在开始我将假设

ThingWithIncrediblyLargeArrays
是一个结构体。

Array
是复制-。对于要复制的数组存储,它必须

在 A 和 B 两种情况下,

hot
的 getter 返回
ThingWithIncrediblyLargeArrays
的副本,但副本中的数组将共享相同的存储,因为您没有写入
hugestuff.hot.enormousArray

但是,

hot
并不完全像指针。如果你这样做:

hugeStuff.hot.enormousArray[someIndex] = something

hot
返回
ThingWithIncrediblyLargeArrays
的副本,它与
dataSources[currentThing]
共享数组存储。然后您修改了
enormousArray
返回的副本的
hot
。现在数组存储无法共享,因此整个数组存储将被复制。

您可以将其视为:

let temp = hugeStuff.hot
temp.enormousArray[someIndex] = something
hugeStuff.hot = temp

此处并未唯一引用数组存储 -

temp
huge.dataSources[someIndex]
共享存储。

确定数组存储是否被复制的一个好方法是使用 Instruments 中的“Allocations”工具。使用以下代码尝试一下:

struct ThingWithIncrediblyLargeArrays {
    var enormousArray = Array(repeating: 1, count: 1000)
    var searchRows = ["Row1", "Row2", "Row3"]
}

class HugeStuff {
    var dataSources = ["Foo": ThingWithIncrediblyLargeArrays()]
    var currentThing = "Foo"
    
    var hot: ThingWithIncrediblyLargeArrays {
        @inlinable
        get { dataSources[currentThing]! }
        @inlinable
        set { dataSources[currentThing] = newValue }
    }
}

let hugeStuff = HugeStuff()
// run each of these loops separately:

// case A
//for i in 0..<1000 {
//    let x = hugeStuff.hot.enormousArray[i]
//    print(x)
//}

// case B
//for i in 0..<1000 {
//    hugeStuff.hot.searchRows = ["Row \(i)"]
//    print("x")
//}

// case C
//for i in 0..<1000 {
//    hugeStuff.hot.enormousArray[i] = i
//    print("x")
//}

您可以按“数组”进行过滤,您将在案例 C 的 Instruments 中看到类似的内容:

名称

_TtGCs23_ContiguousArrayStorageSi_
ContiguousArrayStorage<Int>
的变形名称。您可以使用
swift demangle
命令对它们进行分解。

© www.soinside.com 2019 - 2024. All rights reserved.