Swift 如何使可选项在Xcode 9.4中可散列
在Xcode 10中,Swift编译器足够聪明,可以:Swift 如何使可选项在Xcode 9.4中可散列,swift,xcode,optional,Swift,Xcode,Optional,在Xcode 10中,Swift编译器足够聪明,可以: 将包装可散列值的选项视为可散列 Xcode>=9.4还将处理包含所有可散列的structs 属性也是可散列的 奇怪的是,即使构建语言是Swift 4,甚至是Swift 3,Xcode 10也将optional视为可散列的 以以下代码为例: struct Foo: Hashable { var string1: String? var string2: String? } 该代码在Xcode 10下编译,并且使用Foo对象的
可散列
值的选项视为可散列
的struct
s
属性也是可散列的
struct Foo: Hashable {
var string1: String?
var string2: String?
}
该代码在Xcode 10下编译,并且使用Foo对象的hashValue可以按预期工作,即使构建语言是Swift 3
但是,在Xcode 9.4中,Foo结构不是自动可散列的,除非您将属性设置为非可选
此代码按照您在Xcode 9.4/Swift 4.1中希望的方式编译和工作:
struct Foo: Hashable {
var string1: String
var string2: String
}
如何在Xcode 9中使选项可散列?我当然可以自己为我的结构实现Hashable
一致性,但是为多部分结构创建好的哈希实际上有点棘手,我不想为此担心
我也想不出一个简单的方法来使可选的
可散列。(同样,这只是XcodeSwift 4.2定义了
作为
特别是
.none
与整数零具有相同的哈希值,与
类型,以及
- 散列值
.some(wrapped)
通过混合
将
与整数1包装在一起
Swift 4.1(随Xcode 9.4提供)已经有了必要的工具来
实施类似的方法:
- 条件一致性,即我们可以定义扩展
extension Optional: Hashable where Wrapped: Hashable
- 如果所有成员都是可哈希的,则类型的可哈希的自动合成
下面是一个可能的实现:
extension Optional: Hashable where Wrapped: Hashable {
struct Combiner: Hashable {
let left: Int
let right: Wrapped
}
public var hashValue: Int {
switch self {
case .none:
return 0.hashValue
case .some(let wrapped):
return Combiner(left: 1, right: wrapped).hashValue
}
}
}
例如:
struct Foo: Hashable {
var string1: String?
var string2: String?
}
let foo = Foo(string1: "1", string2: "2")
print(foo.hashValue) // 2171695307022640119
要使此代码也能用Swift 4.2及更新版本编译,请
扩展方法可以有条件地编译(比较
):
您混淆了Xcode版本和Swift版本。即使使用Xcode 10,也可以使用Swift 3。我想你是在问如何在Swift 4.0或Swift 4.1而不是Swift 4.2中实现这一点?请不要将IDE版本与语言/编译器版本混淆,这是两个截然不同的概念。Swift也可以在Xcode之外编译(也许你应该试试这个来缩小你的问题范围),也可能是相关的(Swift 4.2),而且(Swift 4.2)我非常理解其中的区别。你可能认为语言版本会决定什么有效,什么无效,但我专门测试了它。它似乎是由编译器版本驱动的,而不是由您在IDE中选择的语言版本驱动的。在Xcode 10中,即使选择Swift 3作为语言版本,也会编译带有optionals的结构的版本,而在Xcode 9.4中它不会编译。在升级之前,请使用Sourcery的AutoHashable()。升级时,很容易将其删除并替换为隐式哈希表。我使用了“Xcode 10”和“Xcode 9.4”,因为我没有现成的权限访问这些IDE版本中包含的编译器版本的信息,它描述了我发现的情况。如果你有这方面的信息,这将是有益的。(我几乎总是在Xcode中使用LLVM Swift编译器,除非我正在使用brew构建项目,或者在Pi.EXTABLE上执行Swift。(投票)。这就是我要寻找的。但有一个问题:在可选的可哈希扩展的Swift 4.2版本中,在某些情况下,它将哈希值1和包装值的哈希值结合起来。(我假设这会使foo
和可选
具有不同的哈希值。)您的版本不包含该步骤。不是吗?@duncac:它已经包含了,带有组合器(左:1,右:wrapped)。hashValue
。哈希组合器函数不是公共函数,因此我使用了该“技巧”您可以检查foo.hashValue
和(foo-as-foo?).hashValue
是否不同。-不客气,找到它很有趣!
struct Foo: Hashable {
var string1: String?
var string2: String?
}
let foo = Foo(string1: "1", string2: "2")
print(foo.hashValue) // 2171695307022640119
#if swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))
// Code targeting the Swift 4.2 compiler and above:
// Conditional conformance `Optional: Hashable` defined in the standard library.
#elseif swift(>=4.1) || (swift(>=3.3) && !swift(>=4.0))
// Code targeting the Swift 4.1 compiler and above:
extension Optional: Hashable where Wrapped: Hashable {
// ...
}
#endif