我怎麼能做到這一點?Int和String如何被接受爲AnyHashable?
var dict = [AnyHashable : Int]()
dict[NSObject()] = 1
dict[""] = 2
這意味着NSObject
和String
是不知何故亞型AnyHashable
但AnyHashable
是一個struct
那麼,他們是如何允許這樣做?
我怎麼能做到這一點?Int和String如何被接受爲AnyHashable?
var dict = [AnyHashable : Int]()
dict[NSObject()] = 1
dict[""] = 2
這意味着NSObject
和String
是不知何故亞型AnyHashable
但AnyHashable
是一個struct
那麼,他們是如何允許這樣做?
請考慮Optional
是一個enum
,它也是一種值類型 - 但您可以自由地將String
轉換爲Optional<String>
。答案只不過是編譯器爲你隱式執行這些轉換。
如果我們看一下以下代碼發出的SIL:
let i: AnyHashable = 5
我們可以看到,編譯器插入到_swift_convertToAnyHashable
呼叫:在AnyHashable.swift
// 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 : [email protected](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) : [email protected](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
來看,我們可以看到函數的名稱爲_swift_convertToAnyHashable
,它只是簡單地調用AnyHashable
's initialiser。
@_silgen_name("_swift_convertToAnyHashable")
public // COMPILER_INTRINSIC
func _convertToAnyHashable<H : Hashable>(_ value: H) -> AnyHashable {
return AnyHashable(value)
}
因此,上述代碼僅僅是等效於:
let i = AnyHashable(5)
雖然這是奇怪的是標準庫also implements an extension爲Dictionary
(其@OOPer shows),允許一個字典類型的Key
AnyHashable
將被任何_Hashable
符合類型(我不相信有任何類型符合_Hashable
,但不符合Hashable
)。
對於_Hashable
鍵,下標本身應該正常工作,沒有特殊的過載。而不是默認的下標(這將需要一個AnyHashable
密鑰)可以只將與上述隱式轉換所使用的,如下面的示例示出了:
struct Foo {
subscript(hashable: AnyHashable) -> Any {
return hashable.base
}
}
let f = Foo()
print(f["yo"]) // yo
編輯:在夫特4,前述下標過載和_Hashable
既已經從STDLIB通過this commit除去與描述:
我們有一個隱式轉換到AnyHashable,所以沒有 需要對詞典的特殊標都沒有。
這證實了我的懷疑。
class SomeClass: NSObject {
var something: String = "something"
}
var dict = [AnyHashable: Int]()
var object = SomeClass()
dict = ["a": 1, object: 2]
print(dict["a"]) // result: Optional(1)
print(dict[object]) // result: Optional(2)
var object2 = SomeClass()
dict[object2] = 3
print(dict[object2]) // result: Optional(3)
你可以找到這個代碼,當你的dict[NSObject()] = 1
[
或]
在Xcode的斯威夫特編輯器(在8.3測試版8.2.1,有少許差別)CMD-點擊:
extension Dictionary where Key : _AnyHashableProtocol {
public subscript(key: _Hashable) -> Value?
public mutating func updateValue<ConcreteKey : Hashable>(_ value: Value, forKey key: ConcreteKey) -> Value?
public mutating func removeValue<ConcreteKey : Hashable>(forKey key: ConcreteKey) -> Value?
}
_AnyHashableProtocol
和_Hashable
是隱藏類型,因此您可能需要檢查Swift source code。簡單地說:
_Hashable
是Hashable
隱藏超協議,因此,Int
,String
,NSObject
或所有其它類型的Hashable
符合_Hashable
。
_AnyHashableProtocol
是一個隱藏的協議,其中AnyHashable
是一個符合_AnyHashableProtocol
的唯一類型。
所以,上面的擴展與this code in Swift 3.1非常相似。
extension Dictionary where Key == AnyHashable {
//...
}
你看,當你寫這樣的代碼是這樣的:
var dict = [AnyHashable : Int]()
dict[NSObject()] = 1
dict[""] = 2
您正在使用的擴展定義的subscript
操作。
看看這個,它可能會有所幫助:http://kandelvijaya.com/2016/10/10/swift3-why-anyhashable-how-does-it-work-internally/。我覺得我的回答在這種情況下是無益的,所以我把它刪除了 –