Int 和 String 如何被接受为 AnyHashable? [英] How are Int and String accepted as AnyHashable?
问题描述
我怎么能做到这一点?
var dict = [AnyHashable : Int]()
dict[NSObject()] = 1
dict[""] = 2
这意味着 NSObject
和 String
在某种程度上是 AnyHashable
的 subtype 但 AnyHashable
是一个 struct
那么,他们如何允许这个?
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<字符串>
.答案很简单,编译器会为您隐式地执行这些转换.
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,我们可以看到带有 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 显示),允许对于具有 AnyHashable
类型的 Key
的字典,下标为任何 _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 中,上述下标重载和 _Hashable
已被 这个提交 和描述:
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屋!