如何创建带有返回一个可选值的getter但返回一个非可选值的setter的下标

时间:2018-10-27 10:36:36

标签: swift subscript

我正在编写一个名为TriangularArray<T>的自定义集合。它代表这样的结构:

     x
    x x
   x x x
  x x x x
 x x x x x

其中每个x是数组中的元素。我可以使用行号和索引号(都从零开始)访问元素。例如,访问以下内容的(4,2):

     a
    b c
   d e f
  g h i j
 k l m n o

将得到m(第5行,该行的第三个值)。

我使用[[T]]作为后备数组,并编写了这样的下标:

subscript(_ row: Int, _ index: Int) -> T? {
    get {
        // innerArray is the [[T]] used for backing
        if row < 0 || row >= innerArray.count {
            return nil
        }
        if index < 0 || index > row {
            return nil
        }
        return innerArray[row][index]
    }

    set {
        if row < 0 || row >= innerArray.count {
            return
        }
        if index < 0 || index > row {
            return
        }
        innerArray[row][index] = newValue!
    }
}

逻辑是,如果您访问不存在的行和索引,如(1,3),则下标将返回nil。但是,通过使下标返回T?,在setter中的newValue也变得可选,我必须强行打开它。

我真的很想在编译时检查这种事情:

triangularArray[0, 0] = nil // this should be a compile time error

我尝试在Google上查找此内容,但我只发现了这个question,这已经过时了。当然,我们可以在Swift 4.2中做得更好,对吧?

2 个答案:

答案 0 :(得分:0)

只有Swift 4.2可以帮助您在我们的代码中标记此类问题,但我认为4.1或更低版本是不可能的。

Swift 4.2示例:

#if true
   #error("add here your compiler error")
#endif

答案 1 :(得分:0)

不幸的是,由于Swift的大小是动态的,并且在编译时不知道,因此无法与Swift(以及其他使用动态数组的语言)一起使用(在程序运行时可以用任何值初始化)。正在运行)。
例如,如果TriangularArray<T>的大小为1,则[0, 0] 是有效元素,并且编译器无法事先知道。
在标准库中,尝试访问array[-1]之类的数组时没有编译时错误-这将始终编译,但始终会导致运行时错误。

我认为您当前使用可选的解决方案似乎是这里的最佳方案。您还将与Array的工作方式保持一致,并在给出无效下标时触发fatalError
一种替代方法是在Index中创建一个自定义TriangularArray结构,该结构表示三角形的索引,并且可以选择使用xy值构建(尽管这会使事情复杂化)相当多。)

PS:此答案假设TriangularArray<T>可以具有任意高度的三角形(可以在运行时指定高度),因为问题中未指定。如果高度是在编译时定义的,则可以对边界进行硬编码,并且可以像提到的#error一样使用@Raul Mantilla。