我如何创建一个 getter 的下标 returns 是可选的,而 setter 是 returns 非可选的
How can I create a subscript with a getter that returns an optional, but a setter that returns a non-optional
我正在编写一个名为 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),下标将 return nil
。但是,通过使下标return T?
,setter中的newValue
也成为可选的,我必须强制解包它。
我真的很想对这种事情进行编译时检查:
triangularArray[0, 0] = nil // this should be a compile time error
我试着在 Google 上查找这个,但我只找到这个 ,这是非常过时的。我们当然可以在 Swift 4.2 中做得更好,对吧?
只有 Swift 4.2 可以帮助您在我们的代码中标记此类问题,我认为 4.1 或更低版本不可能。
Swift 4.2 例子:
#if true
#error("add here your compiler error")
#endif
不幸的是,Swift(以及其他使用动态数组的语言)不可能做到,因为数组的大小是动态的并且在编译时不知道(它可以用程序为 运行).
时的任意值
例如,如果 TriangularArray<T>
的大小为 1
,则 [0, 0]
是一个有效元素 ,而编译器无法事先知道。
在标准库中,当您尝试访问像 array[-1]
这样的数组时,不会出现编译时错误 - 这将始终编译但始终会导致运行时错误。
我认为您目前使用可选的解决方案似乎是这里的最佳方案。您还与 Array
的工作方式保持一致,并在给出无效下标时触发 fatalError
。
另一种方法是在 TriangularArray
中创建一个自定义 Index
结构来表示三角形的索引,并且可以选择从 x
和 y
值构建(尽管这可能会使事情复杂化相当多)。
PS:这个答案假定 TriangularArray<T>
可以有一个任意高度的三角形(可以在运行时指定的高度),因为它没有在问题中指定。如果高度是在编译时定义的,那么边界可以是硬编码的,就像@Raul Mantilla 提到的那样 #error
可以使用。
我正在编写一个名为 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),下标将 return nil
。但是,通过使下标return T?
,setter中的newValue
也成为可选的,我必须强制解包它。
我真的很想对这种事情进行编译时检查:
triangularArray[0, 0] = nil // this should be a compile time error
我试着在 Google 上查找这个,但我只找到这个
只有 Swift 4.2 可以帮助您在我们的代码中标记此类问题,我认为 4.1 或更低版本不可能。
Swift 4.2 例子:
#if true
#error("add here your compiler error")
#endif
不幸的是,Swift(以及其他使用动态数组的语言)不可能做到,因为数组的大小是动态的并且在编译时不知道(它可以用程序为 运行).
时的任意值
例如,如果 TriangularArray<T>
的大小为 1
,则 [0, 0]
是一个有效元素 ,而编译器无法事先知道。
在标准库中,当您尝试访问像 array[-1]
这样的数组时,不会出现编译时错误 - 这将始终编译但始终会导致运行时错误。
我认为您目前使用可选的解决方案似乎是这里的最佳方案。您还与 Array
的工作方式保持一致,并在给出无效下标时触发 fatalError
。
另一种方法是在 TriangularArray
中创建一个自定义 Index
结构来表示三角形的索引,并且可以选择从 x
和 y
值构建(尽管这可能会使事情复杂化相当多)。
PS:这个答案假定 TriangularArray<T>
可以有一个任意高度的三角形(可以在运行时指定的高度),因为它没有在问题中指定。如果高度是在编译时定义的,那么边界可以是硬编码的,就像@Raul Mantilla 提到的那样 #error
可以使用。