对 swift 中内部数组的本地引用

Local reference to inner array in swift

我来自 C# 世界,习惯于将数组作为引用类型。据我了解,在 swift 中,数组是值类型,但它们试图充当参考类型。

我实际上不知道如何询问我需要什么(我认为当我需要知道答案才能提出问题时就是这种情况),但在 C# 中我会说我需要存储一个引用将锯齿状数组的内部数组转换为局部变量。

考虑以下代码:

// a function to change row values in-place
func processRow(inout row : [Int], _ value : Int)
{
    for col in 0..<row.count
    {
        row[col] = value;
    }
}

// a function to change matrix values in-place
func processMatrix(inout matrix : [[Int]])
{
    for rowIdx in 0..<matrix.count
    {
        // (1) Works with array in-place
        processRow(&(matrix[rowIdx]), -1)

        // (2) Creates local copy
        var r = matrix[rowIdx]; // <--- What to write here to not make a copy but still have this local variable?
        processRow(&r, -2);
    }
}

var matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

processMatrix(&matrix)

print(matrix) // outputs [[-1, -1, -1], [-1, -1, -1], [-1, -1, -1]]

Swift 这里是沙箱 http://swiftlang.ng.bluemix.net/#/repl/8608824e18317e19b32113e1aa08deeb4ec5ab96ed8cdbe1dbfb4e753e87d528

在这里我想就地处理多维数组,这样我就不会创建数组的副本或数组的一部分。

在选项 (1) 中,我将所有内容都更改为“-1”,它起作用了,但是为此使用了附加功能。

在选项 (2) 中,我尝试使用局部变量来存储 matrix[rowIdx],但它实际上创建了一个内部数组的副本——这不是我想要的;使用此变量会更改数组的副本,而不是原始数组。

如何使用局部变量而不是函数来实现选项 (1) 中的结果?即,如何获取内部数组的引用并将其放入局部变量?

我会理解答案 "there's no way for this",但我希望此类答案附有一些 Apple 参考资料。

我不相信有一种方法可以在不制作副本的情况下将数组复制到局部变量中。这就是值类型在 Swift 中的工作方式。 Says Apple:

The most basic distinguishing feature of a value type is that copying — the effect of assignment, initialization, and argument passing — creates an independent instance with its own unique copy of its data[.]

And here:

A value type is a type whose value is copied when it is assigned to a variable or constant, or when it is passed to a function...

[...]

All structures and enumerations are value types in Swift. This means that any structure and enumeration instances you create—and any value types they have as properties—are always copied when they are passed around in your code.

它只是值类型定义的一部分 - 每个数组都是值类型。

获得所需结果的最简单方法是将 r 的值重新分配给要在 matrix 中更改的行:

// (2) Creates local copy
var r = matrix[rowIdx]   
processRow(&r, -2)
matrix[rowIdx] = r

最接近您建议的是使用指针:UnsafeMutablePointerUnsafePointer 等。但这确实与 Swift 的设计方式背道而驰使用。但是,如果您愿意,它看起来像这样:

func processRow(ptr: UnsafeMutablePointer<Int>, _ value : Int, count: Int) {
    for col in 0..<count {
        ptr.advancedBy(col).memory = value
    }
}

func processMatrix(inout matrix : [[Int]]) {
    for rowIdx in 0..<matrix.count {
        
        let r = UnsafeMutablePointer<Int>(matrix[rowIdx])
        processRow(r, -2, count: matrix[rowIdx].count)
    }
}

var matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

processMatrix(&matrix)
print(matrix)   // [[2, 2, 2], [2, 2, 2], [2, 2, 2]]

Swift 数组在处理可变数据时非常痛苦。有两种方法可以解决这个问题:

1) 使用 NSMutableArray

import Foundation

func processRow(_ row : NSMutableArray, _ value : Int) {
    for col in 0..<row.count {
        row[col] = value;
    }
}

func processMatrix(_ matrix : inout [NSMutableArray]) {
    for rowIdx in 0..<matrix.count {
        let r = matrix[rowIdx]
        processRow(r, -2);
    }
}

var matrix = [
    NSMutableArray(array: [1, 2, 3]),
    NSMutableArray(array: [4, 5, 6]),
    NSMutableArray(array: [7, 8, 9])
]

processMatrix(&matrix)

print(matrix) // outputs , <__NSArrayM 0x6000027a1560>(-2,-2,-2)]

2) 使用 class 包装器

class Wrapper<T: CustomDebugStringConvertible>: CustomDebugStringConvertible {
    var value: T

    init(_ value: T) {
        self.value = value
    }

    var debugDescription: String {
        return value.debugDescription
    }
}

func processRow(_ row : Wrapper<[Int]>, _ value : Int) {
    for col in 0..<row.value.count {
        row.value[col] = value;
    }
}

func processMatrix(_ matrix : inout [Wrapper<[Int]>]) {
    for rowIdx in 0..<matrix.count {
        let r = matrix[rowIdx]
        processRow(r, -2);
    }
}

var matrix = [
    Wrapper([1, 2, 3]),
    Wrapper([4, 5, 6]),
    Wrapper([7, 8, 9])
]

processMatrix(&matrix)

print(matrix) // outputs [[-2, -2, -2], [-2, -2, -2], [-2, -2, -2]]

不过看起来不太好看