Изменяемый указатель на строку в двумерном массиве - PullRequest
0 голосов
/ 09 марта 2019

Предположим, что существует двумерный массив

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 голосов
/ 09 марта 2019

Вот еще одна простая версия для отображения матрицы с изменяемым [[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. 

Надеюсь, это полезно.

0 голосов
/ 09 марта 2019

Вот как вы можете изменить фактический указатель вашего массива, но я не уверен, имеет ли он какое-либо реальное значение по сравнению с существующей копией массива. Поскольку типы значений всегда копируются, мы получаем указатель, меняем значение и назначаем новое значение указателю.

Но лучше делать это обычным способом, рассматривая массив как тип значения. Также, если ваш класс является ссылочным типом, это сильно упрощает ситуацию.

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
}
0 голосов
/ 09 марта 2019

То, чего вы действительно пытаетесь достичь, это добавить поддержку значений 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» прямо в названии!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...