2016-10-19 23 views
7

Neden Foo<U> değerini Foo<T> türünde bir değere atamam için bana izin vermiyor, burada U T'nin bir alt sınıfıdır? ÖrneğinNeden Swift'de genel bir türün alt sınıfını kullanamıyorum?

:

class Cheese { 
    let smell: Int 
    let hardness: Int 
    let name: String 

    init(smell: Int, hardness: Int, name: String) { 
     self.smell = smell 
     self.hardness = hardness 
     self.name = name 
    } 

    func cut() { 
     print("Peeyoo!") 
    } 
} 

class Gouda: Cheese { 
    let aged: Bool 

    init(smell: Int, hardness: Int, name: String, aged: Bool) { 
     self.aged = aged 
     super.init(smell: smell, hardness: hardness, name: name) 
    } 

    override func cut() { 
     print("Smells delicious") 
    } 
} 

class Platter<Food> { 
    var food: Food 

    init(food: Food) { 
     self.food = food 
    } 
} 

let goudaCheese = Gouda(smell: 6, hardness: 5, name: "Gouda", aged: false) 
let goudaPlatter = Platter(food: goudaCheese) //Platter<Gouda> 

//error: cannot assign value of type 'Platter<Gouda>' to type 'Platter<Cheese>' 
let platter: Platter<Cheese> = goudaPlatter 

Ama neden çalışmıyor? Bir değişkene, türünün bir alt sınıfı olan bir nesneyi atayabilirsiniz, ör.

let gouda = Gouda(smell: 6, hardness: 5, name: "Gouda", aged: false) 
let cheese: Cheese = gouda 

Ve koleksiyonlara alt sınıflarını ekleyebilirsiniz:

let plainCheese = Cheese(smell: 2, hardness: 5, name: "American") 
let gouda = Gouda(smell: 6, hardness: 5, name: "Gouda", aged: false) 
var cheeses: [Cheese] = [plainCheese] 
cheeses.append(gouda) 

Yani ne kadar farklı let platter: Platter<Cheese> = goudaPlatter nedir? Çalışırsa güvenli olmadığı durumlar var mı? Swift'in şu anki versiyonunun bir kısıtlaması mı?

+0

olumlu değil, ama 'Tabağı ' için 'Tabağı ' değiştirebilir (ve sonradan 'var yemek: t ',' init (gıda: T) ')? – Connor

+2

Jenerikler Swift'de değişmezler - tip sisteminin gözünde, 'Platter ' ve 'Platter ' tamamen birbirleriyle ilgisizdir. Aralarında dönüşüm yapmak isterseniz, bu dönüşümü gerçekleştirmek için kodu yazmanız gerekir. 'Array', derleyicinin bu dönüşümü sizin için yapması için sahnenin arkasında bir sihir yaptığı özel bir durumdur (örneğin [bu Soru-Cevap] bölümüne bakın (http://stackoverflow.com/questions/37188580/why-isnt- somestruct dönüştürülemeyen-to-herhangi)). – Hamish

+0

İlgili (belki de dupe?): [Swift türünde \ [String: Class \] türünde bir Dictionary sınıf değerini nasıl depolayabilirim?] (Http://stackoverflow.com/q/ 38590548/2976878) – Hamish

cevap

5

type erasure adlı teknik kullanarak bu konu üzerinde çalışabilirsiniz. Temel olarak, temel sınıf detayını jenerikten gizleyen bir "sarmalayıcı" yapı yaratırsınız. İdeal değil, ama yapmaya çalıştığınız şeye benzer bir şeyi başarmanıza izin veriyor.

class Cheese { 
    func doSomethingCheesy() { 
     print("I'm cheese") 
    } 
} 

class Gouda: Cheese { 
    override func doSomethingCheesy() { 
     print("I'm gouda") 
    } 
} 

struct AnyCheese { 
    let cheese: Cheese 
} 

class Container<T> { 
    init(object: T) { 
     self.object = object 
    } 
    let object: T 
} 

let cheese = Cheese() 
let cheeseContainer: Container<AnyCheese> = Container(object: AnyCheese(cheese: cheese)) 

let gouda = Gouda() 
let goudaContainer: Container<AnyCheese> = Container(object: AnyCheese(cheese: gouda)) 

cheeseContainer.object.cheese.doSomethingCheesy() // prints "I'm cheese" 
goudaContainer.object.cheese.doSomethingCheesy() // prints "I'm gouda" 
+0

Cevapınızı yukarı doğru çevirdim, çünkü bu tip silme işleminin iyi bir açıklaması ve eminim ki bu soruyu bulan kişilere yardımcı olacaktır. Bununla birlikte, onu kabul edildiği gibi işaretlemedim çünkü Swift'in neden böyle bir çalışma peşinde koşmak yerine bu şekilde davrandığına dair bir açıklama istiyordum. Sorumluluk hakkındaki yorumların iyi bir cevap olarak yeniden çalışılabileceğini düşünüyorum. – ConfusedByCode

İlgili konular