swift

时间:2016-01-18 21:19:40

标签: c# arrays swift jagged-arrays mutability

我来自C#world,并习惯于数组作为引用类型。据我所知,在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)中,我将所有内容更改为&#34; -1&#34;,它可以正常工作,但是为此使用了附加功能。

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

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

我会理解答案&#34;没有办法解决这个问题&#34;但是我希望这些答案可以附带一些Apple裁判。

2 个答案:

答案 0 :(得分:1)

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

  

值类型最基本的区别特征是复制 - 赋值,初始化和参数传递的效果 - 创建一个独立的实例,它具有自己唯一的数据副本[。]

And here

  

值类型是一种类型,当将值分配给变量或常量时,或者将值传递给函数时,将复制该值...

     

[...]

     

所有结构和枚举都是Swift中的值类型。这意味着您创建的任何结构和枚举实例以及它们作为属性的任何值类型在代码中传递时始终会被复制。

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

获得所需结果的最简单方法就是将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]]

答案 1 :(得分:1)

在处理可变数据时,快速数组非常痛苦。有两种解决方法:

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 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]]

但是看起来不太好。