swift中的下标和协议

Mai*_*aux 3 protocols subscript swift

我正在定义一个协议(用于信息隐藏目的),它具有"下标"功能,同时具有getter和setter.然后我定义了一个实现该协议的类.

问题的简短版本:如果我在类的对象上使用下标(作为左值,从而使用setter),一切都按预期工作.如果我在刚刚声明协议类型的对象上执行此操作,则会出现"无法分配此表达式的结果"错误.

长版.我有一个Int的董事会.板是2D矩阵.我通过BoardType协议公开了Board类型.

protocol BoardType {
    var width: Int { get }
    var height: Int { get }
    subscript(x: Int, y: Int) -> Int { get set }
}

class Board: BoardType {

    let width, height: Int
    var matrix: Array2D<Int>

    init(width: Int, height: Int) {
        self.width = width
        self.height = height
        matrix = Array2D<Int>(cols: width, rows: height, defaultValue: 0)
    }

    subscript(x: Int, y: Int) -> Int {
        get {
            return matrix[x, y]
        }
        set {
            matrix[x, y] = newValue
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Array2D的实现是标准的:

class Array2D<T> {

    var cols: Int, rows: Int
    var matrix: [T]

    init(cols: Int, rows:Int, defaultValue: T) {
        self.cols = cols
        self.rows = rows
        matrix = Array(count: cols*rows, repeatedValue: defaultValue)
    }

    subscript(x: Int, y: Int) -> T {
        get {
            return matrix[cols * y + x]
        }
        set {
            matrix[cols * y + x] = newValue
        }
    }

    func colCount() -> Int {
        return self.cols
    }

    func rowCount() -> Int {
        return self.rows
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,如果我执行以下操作,它可以工作:

    let board = Board(width: 4, height: 4)
    board[1, 1] = 10
Run Code Online (Sandbox Code Playgroud)

相反,如果我使用原型,我会收到错误

    let board : BoardType = Board(width: 4, height: 4)
    board[1, 1] = 10
Run Code Online (Sandbox Code Playgroud)

为什么?

Nat*_*ook 19

编译器正在这样做,因为你已经声明了第二个,let可能是一个值类型,在这种情况下,下标setter将是一个变异表达式.两个修复 - var在声明时使用BoardType:

var board : BoardType = Board(width: 4, height: 4)
board[1,1] = 10
Run Code Online (Sandbox Code Playgroud)

或制作BoardType课程协议:

protocol BoardType: class {
    var width: Int {get}
    var height: Int {get}
    subscript(x:Int, y:Int) -> Int {get set}
}
Run Code Online (Sandbox Code Playgroud)