指向二维数组中行的可变指针

时间:2019-03-09 01:17:48

标签: arrays swift pointers

假设有一个二维数组

var myArray: [[MyClass]]

由于数组是Swift中的值类型,因此赋值类似

let line = myArray[lineNumber]

将创建一个副本,而不是引用实际的行。

为了修改数组上的行(例如在行中插入/删除元素)而不复制元素并避免大量使用索引(即在代码中多次使用myArray[lineNumber]),我尝试了C样式指针的方法。

分配

let rowPointer = UnsafePointer(myArray[rowNumber])

似乎没有按预期方式工作,是指myArray[rowNumber][0]而不是整行。

但是

let rowPointer = UnsafePointer(myArray) + rowNumber

编译没有错误并且可以解决问题,因此,rowPointer.pointee可以访问整行

由于我还需要通过插入/附加元素来修改行,因此我尝试了可变指针:

let rowPointer = UnsafeMutablePointer(myArray) + rowNumber

但是此分配会产生编译错误:

无法调用initializer for type 'UnsafeMutablePointer<_>' with an argument list of type '([[MyClass]])'

有没有一种方法可以通过可变指针访问行?

3 个答案:

答案 0 :(得分:0)

您真正想实现的目标是添加对L值的支持。可以分配或就地编辑的值。在Swift中,这是通过下标运算符实现的:

struct Matrix<T> {
    var rows: [[T]]

    init(rows: [[T]]) { self.rows = rows }

    init(width: Int, height: Int, initialElement: T) {
        let rows = (0..<height).map { _ in
            return Array(repeating: initialElement, count: width)
        }
        self.init(rows: rows)
    }

    subscript(row: Int, col: Int) -> T {
        get { return self.rows[row][col] }
        set { self.rows[row][col] = newValue }
    }
}

extension Matrix: ExpressibleByArrayLiteral {
    init(arrayLiteral: [T]...) {
        self.init(rows: arrayLiteral)
    }
}

extension Matrix: CustomDebugStringConvertible {
    var debugDescription: String {
        let height = rows.first?.count ?? 0
        let rowText = rows.map { row in
            row.map { element in String(describing: element) }.joined(separator: ", ")
        }.joined(separator: "],\n\t[")

        return """
            Matrix(width: \(rows.count), height: \(height), rows:
                [\(rowText)]
            )
            """
    }
}

var matrix: Matrix = [
    ["A", "B"],
    ["C", "D"],
]

print(matrix)

matrix[0, 1] = "X"

print(matrix)

在不安全的指针方法上,我强烈建议这样做,它可能导致您遇到各种悬空的指针或缓冲区溢出问题。毕竟,“ Unsafe”名称就在那里!

答案 1 :(得分:0)

这是另一个显示可变[[Any]]矩阵的简单版本。

  let row1: NSMutableArray = [1,"22",3]
  let row2: NSMutableArray = [2,"33",3]
  let row3: NSMutableArray = [4,"4",5]

  let matrix: [NSMutableArray] = [row1, row2, row3] // Here matrix is an immutable. This is the difference from other answers.

  matrix[0][1] =  22
  matrix[0][2] =  "23"
  matrix[0][3] =  "2333"

  print(type(of:matrix[0][1])) //  __NSCFNumber
  print(type(of:matrix[0][2])) // NSTaggedPointerString

这更重要。

  let line1 = matrix[0] // here `let` again
  line1[2] = 33444

  print(matrix)  //matrix has changed. That means it is using reference. 

希望它有用。

答案 2 :(得分:0)

这是修改数组实际指针的方法,但是我不确定这对现有数组副本是否有实际价值。由于值类型总是被复制,因此我们获取指针,更改值并为指针分配新值。

但是,最好将数组视为值类型,以通常的方式进行。同样,如果您的类是引用类型,则可以简化很多事情。

var myArray: [[Int]] = [[1, 2, 3], [4, 5, 6]]

withUnsafeMutablePointer(to: &myArray) { pointer  in
    print(pointer)
    var pointee = pointer.pointee
    pointee[1][1] = 10
    pointer.pointee = pointee
}