简体   繁体   English

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

[英]A mutable pointer to a row in a two-dimensional array

Assume there is a two-dimensional array 假设有一个二维数组

var myArray: [[MyClass]]

Since array is a value type in Swift, assignment like 由于数组是Swift中的值类型,因此赋值就像

let line = myArray[lineNumber]

will create a copy, instead of referring to an actual row. 将创建一个副本,而不是引用实际的行。

In order to modify rows on an array (like inserting / deleting elements in a row) without copying elements and avoiding abundant use of indexing (ie having myArray[lineNumber] many times in the code), I tried C-style approach with pointers. 为了修改数组上的行(例如在行中插入/删除元素)而不复制元素并避免大量使用索引(即在代码中多次使用myArray[lineNumber] ),我尝试了使用C风格的指针方法。

Assignment 分配

let rowPointer = UnsafePointer(myArray[rowNumber])

doesn't appear to work the expected way, referring to myArray[rowNumber][0] rather than to a whole row. 似乎没有按预期方式工作,是指myArray[rowNumber][0]而不是整行。

However, 然而,

let rowPointer = UnsafePointer(myArray) + rowNumber

compiles without error and does the trick, so this way the whole row can be accessed by rowPointer.pointee 可以rowPointer.pointee进行编译并成功完成操作,因此rowPointer.pointee可以访问整行

Since I also need to modify the row by inserting / appending elements, I tried mutable pointer: 由于我还需要通过插入/追加元素来修改行,因此我尝试了可变指针:

let rowPointer = UnsafeMutablePointer(myArray) + rowNumber

However this assignment gives a compilation error: 但是,此分配会产生编译错误:

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

Is there a way to access a row by a mutable pointer? 有没有一种方法可以通过可变指针访问行?

What you're really tryign to achieve is add support for L values. 您真正想做到的是添加对L值的支持。 Values that can be assigned to or edited in place. 可以分配或就地编辑的值。 In Swift, that's achieved with the subscript operator: 在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)

I would strongly recommend this over the unsafe pointer approach, which can lead you to all kinds of dangling pointer or buffer overflow issues. 我强烈建议您使用不安全的指针方法,因为它可能导致您遇到各种悬空的指针或缓冲区溢出问题。 After all, "Unsafe" is right there in the name! 毕竟,“ Unsafe”名称就在那里!

Here is another simple version to show matrix with mutable [[Any]]. 这是另一个显示可变[[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

This is more important. 这更重要。

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

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

Hope it's useful. 希望它有用。

Here is how you can modify the actual pointer of your array but I am not sure if this has any real value over the existing array copy. 这是修改数组实际指针的方法,但是我不确定它在现有数组副本上是否有任何实际价值。 Since, value types are always copied, so we get the pointer, change value and assign new value to the pointer. 由于值类型始终被复制,因此我们获得了指针,更改了值并为指针分配了新值。

But, it is better that you do it in usual way, considering array as a value type. 但是,最好将数组视为值类型,以通常的方式进行。 Also if your class is reference type, it simplifies things a lot. 同样,如果您的类是引用类型,则可以简化很多事情。

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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM