【问题标题】:How can I create a subscript with a getter that returns an optional, but a setter that returns a non-optional如何使用返回可选的getter创建下标,但返回非可选的setter
【发布时间】:2019-03-31 22:34:31
【问题描述】:

我正在编写一个名为 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 中做得更好,对吧?

【问题讨论】:

  • 我认为情况没有改变。下标 getter/setter 仍然返回/采用相同的类型。
  • @MartinR 我明白了。也许我可以利用其他一些语言特性来实现类似的审美,同时禁止nil...
  • 我唯一想到的是定义两个下标方法:一个获取/设置一个非可选值,另一个只获取下标返回一个可选值(如“安全数组访问器”目前在forums.swift.org/t/add-accessor-with-bounds-check-to-array/…讨论)
  • 事实上,stdlib 处理这个问题的方式是让这些可选返回的访问器只获取,例如(Bidirectional)Collectionfirstlast 属性。
  • 另一个选项(也来自那个 Swift 论坛讨论)是定义一个访问器方法 elementAt(row:index:) -&gt; T? - 另一个问题是你是否真的希望 setter 默默地忽略无效索引,或者如果它应该崩溃。

标签: swift subscript


【解决方案1】:

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

Swift 4.2 示例:

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

【讨论】:

    【解决方案2】:

    不幸的是,使用 Swift(和其他使用动态数组的语言)是不可能的,因为数组的大小是动态的并且在编译时是不知道的(它可以在程序运行时用任何值初始化运行)。
    例如,如果TriangularArray&lt;T&gt; 的大小为1,那么[0, 0] 是一个有效元素,编译器无法提前知道这一点。
    在标准库中,当您尝试访问像 array[-1] 这样的数组时不会出现编译时错误 - 这将始终编译,但始终会导致运行时错误。

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

    PS:此答案假定 TriangularArray&lt;T&gt; 可以具有任意高度的三角形(可以在运行时指定的高度),因为它没有在问题中指定。如果高度是在编译时定义的,那么可以硬编码边界,​​并且可以使用 @Raul Mantilla 提到的 #error

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-30
      • 2015-06-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多