如何在Xcode 9.4中使Optionals Hashable

时间:2018-11-09 00:52:11

标签: swift xcode optional

在Xcode 10中,Swift编译器足够聪明,可以:

  1. Treat可选,将describe 'my_method(my_method_argument)' do include_context 'rake' it 'calls my method' do expect(described_class.send(:my_method, my_method_argument)).to eq(expected_results) end end 的值包装为Hashable

  2. Xcode> = 9.4也将处理包含所有Hashable的{​​{1}} 属性也为struct

奇怪的是,即使构建语言是Swift 4甚至是Swift 3,Xcode 10也会将Optionals视为Hashable。

以下面的代码为例:

Hashable

该代码在Xcode 10下编译,并且即使构建语言是Swift 3,使用Foo对象的hashValue也会按预期工作!

但是,在Xcode 9.4中,除非您将属性设为非可选属性,否则Foo结构不会自动哈希。

此代码可以按您希望在Xcode 9.4 / Swift 4.1中进行编译和工作:

Hashable

如何在Xcode 9中使可选项struct Foo: Hashable { var string1: String? var string2: String? } ?我当然可以为自己的结构实现struct Foo: Hashable { var string1: String var string2: String } 一致性,但是为多部分结构创建良好的哈希值实际上有点棘手,而且我不必为此担心。

我也想不出一种简单的方法来制作可选的Hashable。 (再次,这只是Xcode

1 个答案:

答案 0 :(得分:2)

Swift 4.2 定义了条件Optional: Hashable的符合性 Optional.swift

extension Optional: Hashable where Wrapped: Hashable {
  //  ...
  public func hash(into hasher: inout Hasher) {
    switch self {
    case .none:
      hasher.combine(0 as UInt8)
    case .some(let wrapped):
      hasher.combine(1 as UInt8)
      hasher.combine(wrapped)
    }
  }
}

特别是

  • .none具有与整数零相同的哈希值,而与 类型和
  • 哈希值.some(wrapped)是通过混合以下项的哈希值获得的: wrapped和整数1。

Swift 4.1 (Xcode 9.4随附)已经具有必要的工具来 实现类似的方法:

  • 条件符合性,即我们可以定义扩展名

    extension Optional: Hashable where Wrapped: Hashable
    
  • 如果所有成员均为Hashable,则自动为类型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和更高版本中进行编译, 扩展方法可以有条件地编译(比较 SE-0212 Compiler Version Directive):

#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