当引用同一变量时,Swift数组的内存地址会发生变化。

4

我正在学习Python,并想确认一下Objective-C和Swift中的某种行为。

测试如下:

Python

def replace(list):
    list[0] = 3
    print(list)

aList = [1, 2, 3]
print(aList)
replace(aList)
print(aList)

Objective-C

- (void)replace:(NSMutableArray *)array {
    array[0] = @1;
    NSLog(@"array: %@, address: %p\n%lx", array, array, (long)&array);
}

NSMutableArray *array = [@[@1, @2, @3] mutableCopy];
NSLog(@"original: %@, address: %p \n%lx", array, array, (long)&array);
[self replace:array];
NSLog(@"modified: %@, address: %p \n%lx", array, array, (long)&array);

Swift

var numbers = [1, 2, 3]
let replace = { (var array:[Int]) -> Void in
    array[0] = 2
    print("array: \(array) address:\(unsafeAddressOf(array as! AnyObject))")
}

print("original: \(numbers) address:\(unsafeAddressOf(numbers as! AnyObject))")
replace(numbers)
print("modified: \(numbers) address:\(unsafeAddressOf(numbers as! AnyObject))")

除了 Swift 中的地址部分外,所有结果都符合预期。在 Objective-C 中,数组的地址在 originalmodified 中保持不变,但 Swift 的打印结果为:
original: [1, 2, 3] address:0x00007f8ce1e092c0
array: [2, 2, 3] address:0x00007f8ce1f0c5d0
modified: [1, 2, 3] address:0x00007f8ce4800a10

我有没有漏掉什么?


unsafeAddressOf(numbers) 不起作用。这是错误:error: argument type '[Int]' does not conform to expected type 'AnyObject' - funct7
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Rob
1个回答

8
在Swift中,数组具有值语义,而不是Python和Objective-C中的引用语义。你看到不同的地址(以及所有地址)的原因是每次进行as! AnyObject转换时,你实际上是告诉Swift将你的Array<Int>结构体桥接到NSArray的实例上。由于你进行了三次桥接,所以你得到了三个不同的地址。
你不需要考虑Swift数组的地址,但如果你想(暂时)获取数组缓冲区的地址,可以这样做:
func getBufferAddress<T>(array: [T]) -> String {
    return array.withUnsafeBufferPointer { buffer in
        return String(reflecting: buffer.baseAddress)
    }
}

这使您可以看到缓冲区的写时复制(Copy-On-Write)的实际效果:

var numbers = [1, 2, 3]
let numbersCopy = numbers

// the two arrays share a buffer here
print(getBufferAddress(numbers))                 // "0x00007fba6ad16770"
print(getBufferAddress(numbersCopy))             // "0x00007fba6ad16770"

// mutating `numbers` causes a copy of its contents to a new buffer
numbers[0] = 4

// now `numbers` has a new buffer address, while `numbersCopy` is unaffected
print(getBufferAddress(numbers))                 // "0x00007ff23a52cc30"
print(getBufferAddress(numbersCopy))             // "0x00007fba6ad16770"

有没有办法像Objective-C一样获取地址?或者在Swift中这不太相关吗? - funct7
1
在 Swift 中不相关!在答案中添加了一条注释。 - Nate Cook
我设置了一个断点,在lldb中调用了frame var -L numbersframe var -L numbersCopy,内存地址不同。有任何想法为什么它与此处打印的缓冲区地址不匹配? - CyberMew
“Array”被定义为一个结构,它存储指向其存储空间的指针,因此使用lldb命令,我认为您可以看到两个不同变量的堆栈地址,而不是共享基础存储的堆地址。 - Nate Cook

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接