如何将Int和String接受为AnyHashable? [英] How are Int and String accepted as AnyHashable?

查看:239
本文介绍了如何将Int和String接受为AnyHashable?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我怎么能做到这一点?

    var dict = [AnyHashable : Int]()
    dict[NSObject()] = 1
    dict[""] = 2

这意味着NSObjectString在某种程度上是AnyHashable子类型,而AnyHashablestruct,那么,它们如何允许呢?

This implies that NSObject and String are somehow a subtype of AnyHashable but AnyHashable is a struct so, how do they allow this?

推荐答案

请考虑 Optional enum,它也是一个值类型-但是您可以自由地将String转换为Optional<String>.答案很简单,就是编译器会为您隐式执行这些转换.

Consider that Optional is an enum, which is also a value type – and yet you're freely able to convert a String to an Optional<String>. The answer is simply that the compiler implicitly performs these conversions for you.

如果我们查看以下代码发出的SIL:

If we look at the SIL emitted for the following code:

let i: AnyHashable = 5

我们可以看到编译器插入了对_swift_convertToAnyHashable的调用:

We can see that the compiler inserts a call to _swift_convertToAnyHashable:

  // allocate memory to store i, and get the address.
  alloc_global @main.i : Swift.AnyHashable, loc "main.swift":9:5, scope 1 // id: %2
  %3 = global_addr @main.i : Swift.AnyHashable : $*AnyHashable, loc "main.swift":9:5, scope 1 // user: %9

  // allocate temporary storage for the Int, and intialise it to 5.
  %4 = alloc_stack $Int, loc "main.swift":9:22, scope 1 // users: %7, %10, %9
  %5 = integer_literal $Builtin.Int64, 5, loc "main.swift":9:22, scope 1 // user: %6
  %6 = struct $Int (%5 : $Builtin.Int64), loc "main.swift":9:22, scope 1 // user: %7
  store %6 to %4 : $*Int, loc "main.swift":9:22, scope 1 // id: %7

  // call _swift_convertToAnyHashable, passing in the address of i to store the result, and the address of the temporary storage for the Int.
  // function_ref _swift_convertToAnyHashable
  %8 = function_ref @_swift_convertToAnyHashable : $@convention(thin) <τ_0_0 where τ_0_0 : Hashable> (@in τ_0_0) -> @out AnyHashable, loc "main.swift":9:22, scope 1 // user: %9
  %9 = apply %8<Int>(%3, %4) : $@convention(thin) <τ_0_0 where τ_0_0 : Hashable> (@in τ_0_0) -> @out AnyHashable, loc "main.swift":9:22, scope 1

  // deallocate temporary storage.
  dealloc_stack %4 : $*Int, loc "main.swift":9:22, scope 1 // id: %10

查看 AnyHashable.swift ,我们可以看到名称为 _swift_convertToAnyHashable ,它仅调用 AnyHashable的初始化程序.

Looking in AnyHashable.swift, we can see the function with the silgen name of _swift_convertToAnyHashable, which simply invokes AnyHashable's initialiser.

@_silgen_name("_swift_convertToAnyHashable")
public // COMPILER_INTRINSIC
func _convertToAnyHashable<H : Hashable>(_ value: H) -> AnyHashable {
  return AnyHashable(value)
}

因此,上面的代码等效于:

Therefore the above code is just equivalent to:

let i = AnyHashable(5)


尽管很好奇,标准库还为Dictionary实现了扩展名( @OOPer展示),允许使用带有类型为AnyHashableKey要用任何_Hashable符合类型的下标(我不相信有任何符合_Hashable的类型,但没有符合Hashable的类型.)


Although it's curious that the standard library also implements an extension for Dictionary (which @OOPer shows), allowing for a dictionary with a Key of type AnyHashable to be subscripted by any _Hashable conforming type (I don't believe there are any types that conform to _Hashable, but not Hashable).

下标本身应该可以正常工作,并且_Hashable键没有特殊的重载.而是可以将默认下标(将使用AnyHashable键)与上述隐式转换一起使用,如以下示例所示:

The subscript itself should work fine without a special overload for _Hashable keys. Instead the default subscript (which would take an AnyHashable key) could just be used with the above implicit conversion, as the following example shows:

struct Foo {
    subscript(hashable: AnyHashable) -> Any {
        return hashable.base
    }
}

let f = Foo()
print(f["yo"]) // yo

编辑:在Swift 4中,

Edit: In Swift 4, both the aforementioned subscript overload and _Hashable have been removed from the stdlib by this commit with the description:

我们有一个隐式转换为AnyHashable,所以没有 完全需要在Dictionary上有特殊的下标.

We have an implicit conversion to AnyHashable, so there's no need to have the special subscript on Dictionary at all.

证实我的怀疑.

这篇关于如何将Int和String接受为AnyHashable?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆