2017-10-18 105 views
2

我正在建造一個農場,所有可以種植的東西都符合Growable協議。當你種的植物,你可以調用這個FUNC:是否可以在Swift中使用Type作爲字典鍵?

myFarm.planting<T: Growable>(qty: Int, of: T.Type) -> Farm

現在我想農場的每個實例有一個字典實例變種,如:

var crops = [Growable.Type: Int]

的問題是,即使我使可擴展協議繼承Hashable,這不利於Growable 類型成爲Hashable。

換句話說,即使我添加的擴展,可擴展的是這樣的:

extension Growable { 
    static func hashValue { 
     // return some hash 
    } 
} 

...仍然可增長不是哈希的,因爲哈希的協議只涉及的類型實例但不是類型本身。

哦,通常我會放棄,說:「我笨,不會進一步嘗試這個。」

然而,這是斯威夫特,所以我想一定有彎曲的語言我的意志的方式,不管是通過製作一個新的StaticHashable協議,然後用一個新的下標方法來擴展Dictionary類型,或者通過修改Swift的源代碼本身,然後對Evolution列表進行調整。

但是,在我走下這兩條路之前,我認爲問問你天才是否明智,如果已經有辦法做我想做的事,或者做這件事是否令人難以置信的愚蠢,你會向我展示明顯優越的這種方法令我難以置信地不知何故錯過了。

注意:我的意見是,類型本身應該能夠靜態地遵守其funcs沒有被聲明爲靜態的協議,因爲爲什麼消息的發送者應該關心響應的實體是不朽的上帝還是臨時的生物,是以上帝的形象造的?

回答

1

是否可以在Swift中使用Type作爲字典鍵?

那麼其可能,這裏是一個辦法:

protocol Growable { ... } 

struct S : Growable { ... } 
class C : Growable { ... } 

extension Dictionary where Key : LosslessStringConvertible 
{ 
    subscript(index: Growable.Type) -> Value? 
    { 
     get 
     { 
     return self[String(describing: index) as! Key] 
     } 
     set(newValue) 
     { 
     self[String(describing: index) as! Key] = newValue 
     } 
    } 
} 

var d : [String:Int] = [:] 
d[S.self] = 42 
d[C.self] = 24 
print(d) 

打印:

["C": 24, "S": 42] 

如果更改subscript定義:

subscript(index: Any.Type) -> Value? 

喲當然ü可以使用任何類型的鍵:

var d : [String:Int] = [:] 
d[S.self] = 42 
d[C.self] = 24 
d[type(of:d)] = 18 
print(d) 

打印:

["C": 24, "S": 42, "Dictionary<String, Int>": 18] 

我會讓你來決定這是否是明智,但它顯然可能

[注意:您不能將Key限制爲String,因此使用協議LosslessStringConvertible;有可能是一個更好的選擇,雨燕標準庫是一個移動的目標...]

HTH

+0

是的,這是我會做的。我現在很喜歡擴展字典,除了我可能會嘗試製作更通用的StaticHashable協議並在擴展中執行'return index.hashValue'。我真正喜歡的是類型與某些級別的實例無法區分......也許是Swift 5 heh。 – CommaToast

0

您可能會考慮退後一步並檢查您的設計。您可以使用枚舉爲您的Growable工廠建模,這是另一個強大的Swift特性。例如:

protocol Growable { 
    /* ... */ 
} 

enum Vegetable: String, Hashable, Growable { 
    case carrot, lettuce, potato /* ... */ 
} 

enum Mushroom: String, Hashable, Growable { 
    /* ... */ 
} 

struct Farm { 
    var crops = [AnyHashable: Int]() 
    mutating func plant<T: Growable & Hashable>(qty: Int, of growable: T) { 
     crops[growable] = qty 
    } 
} 

使用Hashable作爲具體類型不支持,因此,我們需要使用型擦除AnyHashable結構,而不是 - 協議與自相關類型的需求可能會非常棘手得到正確!

用法:

var myFarm = Farm() 
myFarm.plant(qty: 10, of: Vegetable.carrot) 
myFarm.plant(qty: 20, of: Vegetable.lettuce) 
myFarm.plant(qty: 30, of: Vegetable.potato) 

print(myFarm.crops) 

[AnyHashable(Vegetable.potato):30,AnyHashable(Vegetable.carrot):10,AnyHashable(Vegetable.lettuce):20]


可哈希元類型。關於你的原創設計,來表達你的意圖的正確的方法是:

extension Growable.Type: Hashable { 
    /* make this meta thing hashable! */ 
} 

即制定相應元類型Hashable爲好,但延長元類型尚未被斯威夫特支持;)

+1

我喜歡的枚舉想法。另一種選擇是將作物管理分爲「田間」類型。它將分離邏輯並可能允許每個「Field」限制它可以增長的「作物」。 – PeejWeej

+0

嗯,事情是,可擴展協議需要像'regrowTime'這樣的存儲屬性,並繼承另一個需要'name'和'kind'存儲屬性的協議。現在它們是在每個採用Growable的'struct'中定義的靜態值。如果我做了一個枚舉,因爲枚舉不能存儲屬性,我怎樣才能構造Growable,這樣我就能保證每個枚舉的case都能給我一個更長的時間,一個名字和一種類型? – CommaToast

+0

此外,元組類型無法擴展......非常悲傷......在這裏,我認爲Swift是一種現代語言:S – CommaToast

相關問題