Key에 무엇이든 담을 수있는 Dictionary를 만드는 방법? 또는 보유 할 수있는 모든 가능한 유형
Dictionary
키 유형을 제한하지 않는 을 만들고 싶습니다 (예 NSDictionary
:)
그래서 나는 시도했다
var dict = Dictionary<Any, Int>()
과
var dict = Dictionary<AnyObject, Int>()
결과
error: type 'Any' does not conform to protocol 'Hashable'
var dict = Dictionary<Any, Int>()
^
<REPL>:5:12: error: cannot convert the expression's type '<<error type>>' to type '$T1'
var dict = Dictionary<Any, Int>()
^~~~~~~~~~~~~~~~~~~~~~
네, 사용 할게요 Hashable
var dict = Dictionary<Hashable, Int>()
그러나
error: type 'Hashable' does not conform to protocol 'Equatable'
var dict = Dictionary<Hashable, Int>()
^
Swift.Equatable:2:8: note: '==' requirement refers to 'Self' type
func ==(lhs: Self, rhs: Self) -> Bool
^
Swift.Hashable:1:10: note: type 'Hashable' does not conform to inherited protocol 'Equatable.Protocol'
protocol Hashable : Equatable
^
<REPL>:5:12: error: cannot convert the expression's type '<<error type>>' to type '$T1'
var dict = Dictionary<Hashable, Int>()
^~~~~~~~~~~~~~~~~~~~~~~~~~~
따라서 Hashable
상속 Equatable
되었지만 준수하지 않는 Equatable
??? 이해가 안 돼요 ...
어쨌든 계속 노력해
typealias KeyType = protocol<Hashable, Equatable> // KeyType is both Hashable and Equatable
var dict = Dictionary<KeyType, Int>() // now you happy?
운없이
error: type 'KeyType' does not conform to protocol 'Equatable'
var dict = Dictionary<KeyType, Int>()
^
Swift.Equatable:2:8: note: '==' requirement refers to 'Self' type
func ==(lhs: Self, rhs: Self) -> Bool
^
Swift.Hashable:1:10: note: type 'KeyType' does not conform to inherited protocol 'Equatable.Protocol'
protocol Hashable : Equatable
^
<REPL>:6:12: error: cannot convert the expression's type '<<error type>>' to type '$T1'
var dict = Dictionary<KeyType, Int>()
^~~~~~~~~~~~~~~~~~~~~~~~~~
나는 지금 너무 길을 잃었다. 어떻게 내 코드로 컴파일러를 만족시킬 수 있을까?
다음과 같이 사전을 사용하고 싶습니다.
var dict = Dictionary<Any, Int>()
dict[1] = 2
dict["key"] = 3
dict[SomeEnum.SomeValue] = 4
사용할 수 있다는 것을 알고 Dictionary<NSObject, Int>
있지만 실제로 원하는 것은 아닙니다.
Swift 3 업데이트
이제 AnyHashable
다음과 같은 시나리오를 위해 정확하게 생성 된 유형이 지워진 해시 가능 값을 사용할 수 있습니다 .
var dict = Dictionary<AnyHashable, Int>()
저는 Swift 1.2부터이를 위해 ObjectIdentifier 구조체를 사용할 수 있다고 믿습니다. Hashable (따라서 Equatable)과 Comparable을 구현합니다. 클래스 인스턴스를 래핑하는 데 사용할 수 있습니다. 구현이 == 연산자 내 에서뿐만 아니라 hashValue에 대해 래핑 된 개체의 기본 주소를 사용한다고 생각합니다.
나는 Apple Dev 포럼의 별도 게시물에서이 질문에 대한 교차 게시 / 링크의 자유를 얻었으며이 질문에 대한 답변은 여기에 있습니다 .
편집하다
위 링크의이 답변은 6.1 이상에서 작동합니다.
struct AnyKey: Hashable {
private let underlying: Any
private let hashValueFunc: () -> Int
private let equalityFunc: (Any) -> Bool
init<T: Hashable>(_ key: T) {
underlying = key
// Capture the key's hashability and equatability using closures.
// The Key shares the hash of the underlying value.
hashValueFunc = { key.hashValue }
// The Key is equal to a Key of the same underlying type,
// whose underlying value is "==" to ours.
equalityFunc = {
if let other = $0 as? T {
return key == other
}
return false
}
}
var hashValue: Int { return hashValueFunc() }
}
func ==(x: AnyKey, y: AnyKey) -> Bool {
return x.equalityFunc(y.underlying)
}
Dictionary is struct Dictionary<Key : Hashable, Value>...
which는 Value가 원하는 모든 것이 될 수 있고 Key는 원하는 모든 유형이 될 수 있지만 Key는 Hashable
프로토콜을 준수해야 함을 의미 합니다.
You can't create Dictionary<Any, Int>()
or Dictionary<AnyObject, Int>()
, because Any
and AnyObject
can't guarantee that such a Key conforms Hashable
You can't create Dictionary<Hashable, Int>()
, because Hashable
is not a type it is just protocol which is describing needed type.
So Hashable inherited from Equatable but it does not conform to Equatable??? I don't understand...
But you are wrong in terminology. Original error is
type 'Hashable' does not conform to inherited protocol 'Equatable.Protocol'
That means that Xcode assuming 'Hashable' as some type, but there is no such type. And Xcode treat it as some kind empty type, which obviously does not conform any protocol at all (in this case it does not conform to inherited protocol Equatable
)
Something similar happens with KeyType
.
A type alias declaration introduces a named alias of an existing type into your program.
You see existing type
. protocol<Hashable, Equatable>
is not a type it is protocol so Xcode again tells you that type 'KeyType' does not conform to protocol 'Equatable'
You can use Dictionary<NSObject, Int>
just, because NSObject
conforms Hashable
protocol.
Swift is strong typing language and you can't do some things like creating Dictionary that can hold anything in Key
. Actually dictionary already supports any can hold anything in Key, which conforms Hashable
. But since you should specify particular class you can't do this for native Swift classes, because there is no such master class in Swift like in Objective-C, which conforms air could conform (with a help of extensions) to Hashable
Of course you can use some wrapper like chrisco
suggested. But I really can't imagine why you need it. It is great that you have strong typing in Swift so you don't need to worry about types casting as you did in Objective-C
Hashable
is just a protocol so you can't specify it directly as a type for the Key
value. What you really need is a way of expressing "any type T, such that T implements Hashable
. This is handled by type constraints in Swift:
func makeDict<T: Hashable>(arr: T[]) {
let x = Dictionary<T, Int>()
}
This code compiles.
AFAIK, you can only use type constraints on generic functions and classes.
This doesn't exactly answer the question, but has helped me.
The general answer would be implement Hashable for all your types, however that can be hard for Protocols because Hashable extends Equatable and Equatable uses Self which imposes severe limitations on what a protocol can be used for.
Instead implement Printable and then do:
var dict = [String: Int]
dict[key.description] = 3
The implementation of description has to be something like:
var description : String {
return "<TypeName>[\(<Field1>), \(<Field2>), ...]"
}
Not a perfect answer, but the best I have so far :(
This does not answer the OP's question, but is somewhat related, and may hopefully be of use for some situations. Suppose that what you really want to do is this:
public var classTypeToClassNumber = [Any.Type : Int]()
But Swift is telling you "Type 'Any.Type' does not conform to protocol Hashable".
Most of the above answers are about using object instances as a dictionary key, not using the type of the object. (Which is fair enough, that's what the OP was asking about.) It was the answer by Howard Lovatt that led me to a usable solution.
public class ClassNumberVsClassType {
public var classTypeToClassNumber = [String : Int]()
public init() {
classTypeToClassNumber[String(describing: ClassWithStringKey.self)] = 367622
classTypeToClassNumber[String(describing: ClassBasedOnKeyedItemList3.self)] = 367629
classTypeToClassNumber[String(describing: ClassBasedOnKeyedItemList2.self)] = 367626
classTypeToClassNumber[String(describing: ClassWithGuidKey.self)] = 367623
classTypeToClassNumber[String(describing: SimpleStruct.self)] = 367619
classTypeToClassNumber[String(describing: TestData.self)] = 367627
classTypeToClassNumber[String(describing: ETestEnum.self)] = 367617
classTypeToClassNumber[String(describing: ClassBasedOnKeyedItemList0.self)] = 367624
classTypeToClassNumber[String(describing: ClassBasedOnKeyedItemList1.self)] = 367625
classTypeToClassNumber[String(describing: SimpleClass.self)] = 367620
classTypeToClassNumber[String(describing: DerivedClass.self)] = 367621
}
public func findClassNumber(_ theType : Any.Type) -> Int {
var s = String(describing: theType)
if s.hasSuffix(".Type") {
s = s.substring(to: s.index(s.endIndex, offsetBy: -5)) // Remove ".Type"
}
let classNumber = _classTypeToClassNumber[s]
return classNumber != nil ? classNumber! : -1
}
}
EDIT:
If the classes involved are defined in different modules, and may have conflicting class names if you neglect the module name, then substitute "String(reflecting:" for "String(describing:", both when building up the dictionary and when doing the lookup.
You can use the class name as a Hashable, e.g.:
var dict = [String: Int]
dict[object_getClassName("key")] = 3
See How do I print the type or class of a variable in Swift? for how you might get the class name.
ReferenceURL : https://stackoverflow.com/questions/24119624/how-to-create-dictionary-that-can-hold-anything-in-key-or-all-the-possible-type
'programing' 카테고리의 다른 글
import httplib ImportError : httplib라는 모듈이 없습니다. (0) | 2021.01.14 |
---|---|
드롭 다운 목록의 너비는 어떻게 변경합니까? (0) | 2021.01.14 |
C 및 C ++에서 표 형식 문자를 이스케이프해야합니까? (0) | 2021.01.14 |
Firefox에서 Blob createObjectURL 다운로드가 작동하지 않음 (그러나 디버깅 할 때 작동 함) (0) | 2021.01.14 |
Android에서 개발 모드 및 릴리스 모드 환경 설정 구별 (0) | 2021.01.14 |