提问人:Paulius Liekis 提问时间:5/15/2023 最后编辑:Paulo MattosPaulius Liekis 更新时间:5/19/2023 访问量:103
如何在 Swift 中做类型安全索引?
How to do type-safe indices in Swift?
问:
我正在尝试做这样的事情:
typealias HumanId = Int
typealias RobotId = Int
func getHuman(at index: HumanId) -> Human
func getRobot(at index: RobotId) -> Robot
但就像现在一样,我可以打电话就好了:.getHuman
RobotId
getHuman(at: RobotId(0))
如何使这种类型安全?
我知道我可以做这样的事情:
struct HumanId { let id: Int }
struct RobotId { let id: Int }
...以及一些额外的东西来使这些结构充当索引,但这会导致一些代码重复,并且由于我有 2 个以上的这些 id 类型,我想以某种方式缩短它,也许使用类型别名和泛型以使它们独一无二?
答:
6赞
Paulo Mattos
5/15/2023
#1
您可以利用 Swift 泛型来实现您的目标。引入一个泛型类型,如下所示:Index
struct Index<T>: RawRepresentable {
let rawValue: Int
init(rawValue: Int) { self.rawValue = rawValue }
init(_ rawValue: Int) { self.rawValue = rawValue }
}
然后像这样使用它:
func getHuman(at index: Index<Human>) -> Human { ... }
func getRobot(at index: Index<Robot>) -> Robot { ... }
getHuman(at: Index(1))
getRobot(at: Index(2))
文字索引
在使用文字索引时,您甚至可以使用该协议来提供一些语法糖:ExpressibleByIntegerLiteral
extension Index: ExpressibleByIntegerLiteral {
public init(integerLiteral value: Int) { self.rawValue = value }
}
例如:
getHuman(at: 1)
getRobot(at: 2)
但是以下代码不会生成,因此解决方案仍然是类型安全的:
let someIndex = 123
getHuman(at: someIndex)
error: cannot convert value of type 'Int' to expected argument type 'Index<Human>'
可比指数
正如注释中建议的那样,我们还可以添加一致性(例如,您可以将结构用作符合标准协议的类型的索引):Comparable
Index
Collection
extension Index: Comparable {
static func < (lhs: Index, rhs: Index) -> Bool {
lhs.rawValue < rhs.rawValue
}
}
例:
Index<Human>(1) < Index<Human>(2) // true
评论
1赞
JeremyP
5/15/2023
我喜欢这个答案的优雅。应添加一致性,以便可以将该类型用作符合以下条件的类型的索引Comparable
Collection
评论