ค้นหาอาร์เรย์สำหรับวัตถุประเภทที่ให้ไว้

ฉันมีสัตว์มากมาย ฉันต้องการค้นหาคลาสย่อยบางประเภท อาร์เรย์ของสัตว์จะมีคลาสย่อยเพียงประเภทเดียวเท่านั้น ฉันได้ลองทำสิ่งต่อไปนี้แล้ว ซึ่งไม่ได้ผล ฉันได้รับข้อผิดพลาดในการคอมไพล์ โดยระบุว่า: "animalType ไม่ใช่ประเภท"

public static func getAnimal<T: Animal>(animalType: T.type) -> Animal {
    for animal in self.animals {
        if animal is animalType {
            return animal
        }
    }
}

เป็นไปได้ใน Swift หรือไม่?

ฉันอยากจะเรียกมันว่าแบบนั้น...

AnimalServices.getAnimal(Dog)

person lionpants    schedule 02.03.2015    source แหล่งที่มา
comment
คุณสามารถทำ if Let Cast เป็นประเภทได้ และหากล้มเหลว สัตว์นั้นก็จะไม่ใช่ประเภทนั้น   -  person Ian    schedule 02.03.2015
comment
ฉันแค่ลองสิ่งนั้น if ให้ a = animal as animalType { } คอมไพเลอร์ยังคงบ่นว่า animalType ไม่ใช่ประเภท ฉันกำลังทำให้ไวยากรณ์เสียหายหรือไม่?   -  person lionpants    schedule 02.03.2015


คำตอบ (4)


นี่คือตัวอย่างง่ายๆ สังเกตว่าฉันส่งคืน Animal เผื่อเลือก เนื่องจากการค้นหาอาจล้มเหลว (คอมไพเลอร์ไม่รู้ว่าคุณจะมีสัตว์ประเภทนั้นเพียงตัวเดียวเสมอ):

class Animal {
    let name: String

    init(name: String) {
        self.name = name
    }
}

class Cat: Animal {
    init() {
        super.init(name: "Cat")
    }
}

class Dog: Animal {
    init() {
        super.init(name: "Dog")
    }
}

struct Zoo {
    static var animals: [Animal] = []

    static func getAnimal<T: Animal>(animalType: T.Type) -> Animal? {
        for animal in animals {
            if animal is T {
                return animal
            }
        }
        return nil
    }
}

Zoo.animals.append(Cat())

Zoo.getAnimal(Cat) // Returns the cat as optional
Zoo.getAnimal(Dog)

พูดง่ายๆ ก็คือ T เป็นประเภททั่วไปของคุณ T.Type ระบุว่าคุณกำลังส่งประเภท T เป็นพารามิเตอร์

person Matteo Piombo    schedule 02.03.2015
comment
ฉันอยู่ใกล้ ;) นี่คือสิ่งที่ฉันต้องการ ขอบคุณ! - person lionpants; 02.03.2015
comment
หรือเป็นซับเดียวที่ดี: return animals.filter { $0 is T }.first แม้ว่าจะมีประสิทธิภาพน้อยกว่าก็ตาม - person Rengers; 02.03.2015

คุณสามารถใช้ตัวดำเนินการเอกลักษณ์ === เพื่อตรวจสอบว่าประเภทขององค์ประกอบอาร์เรย์เท่ากับประเภททั่วไปหรือไม่:

if animal.dynamicType === animalType {
    return animal
}
person Antonio    schedule 02.03.2015
comment
ไม่คุณไม่สามารถ คอมไพลเลอร์จะแสดงข้อผิดพลาด: ตัวดำเนินการไบนารี '===' ไม่สามารถใช้กับตัวถูกดำเนินการประเภท 'Animal.Type' และ 'T' - person kellanburket; 02.03.2015
comment
@blacksquare คุณต้องทำอะไรผิด - มันทำงานได้อย่างสมบูรณ์แบบในกระดานเรื่องราว และยิ่งกว่านั้น ฉันไม่ได้ใช้ T ในข้อมูลโค้ดนั้น... - person Antonio; 02.03.2015
comment
ฉันเพิ่งทดสอบโค้ดของคุณใน Swift 1.1 และใช้งานได้ ฉันกำลังทดสอบโดยใช้ Swift 1.2 และเกิดข้อผิดพลาด ดังนั้นระวังในอนาคต ฉันใช้ไวยากรณ์ที่ใช้ในการเปรียบเทียบกับค่าสตริงที่ส่งคืน ซึ่งเป็นการเปรียบเทียบที่ถูกต้องเนื่องจากเป็นทั้งสองสตริง ไม่ว่าในกรณีใดก็ตาม คำตอบที่ดีที่สุดสำหรับคำถามคือเพียงตรวจสอบกับ is T - person kellanburket; 02.03.2015
comment
วิธีแก้ปัญหาของคุณใช้งานได้ แต่ฉันชอบของ @Matteo Piombo มากกว่า ขอบคุณ! - person lionpants; 02.03.2015
comment
@lionpants: ใช่ฉันเห็นด้วย นั่นเป็นวิธีที่ถูกต้องในการทำมัน - person Antonio; 02.03.2015
comment
@blacksquare ฉันทดสอบบน 1.2 แล้วและดูเหมือนว่าจะใช้งานได้ - และตามที่ระบุไว้ข้างต้น ฉันเห็นด้วยกับข้อความล่าสุดของคุณ :) - person Antonio; 02.03.2015
comment
คุณพูดถูก--ฉันขอโทษ เมื่อฉันโหลด Playground ใหม่อีกครั้ง มันก็หยุดแสดงข้อผิดพลาดนั้น เดิมทีฉันมีตัวอย่างของคุณโดยใช้ความเท่าเทียมกัน == แล้วเปลี่ยนไปเป็นตัวตน ===-- มันต้องมีข้อผิดพลาด xcode บางอย่างที่สืบทอดมา ฮึ. คุณทำอะไรได้บ้าง? - person kellanburket; 02.03.2015

คุณไม่สามารถใช้ไวยากรณ์ is หรือ as กับประเภทที่ไม่รู้จัก การเรียงลำดับประเภทการสะท้อนที่คุณกำลังมองหาสามารถทำได้โดยใช้วิธี kindOfClass ของ NSObject ตราบใดที่ Animal เป็นคลาสย่อยของ NSObject:

class Animal: NSObject {

    class func getAnimalOfType<T: Animal>(animals: [Animal], animalType: T.Type) -> Animal? {
        for animal in animals {
            if animal.isKindOfClass(animalType) {
                return animal
            }
        }
        return nil
    }

}

class Zebra: Animal { }
class Whale: Animal { }
var animals = [Zebra(), Whale()]
Animal.getAnimalOfType(animals, animalType: Zebra.self)

หาก Animal ไม่ใช่ประเภทย่อยของ NSObject คุณสามารถทำได้เสมอ--แต่ดูเหมือนว่าจะแฮ็กเล็กน้อยสำหรับฉัน:

 if "\(animal.dynamicType)" == "\(animalType)" {
      return animal
 }
person kellanburket    schedule 02.03.2015

struct Test<T: Hashable> {

    static func test(t: Any) {
        println(t is T)
    }
}

Test<Int>.test(3)

ในตัวอย่างนี้ ฉันกำลังส่งประเภท (Int ในกรณีของฉัน AnimalType ในตัวคุณ) ไปยังโครงสร้างและตัวแปร (Int ของฉัน (3) สัตว์ของคุณ) เป็นพารามิเตอร์ของการทดสอบฟังก์ชันคงที่ ฉันใช้ T: Hashable คุณจะต้องทดสอบกับ T: Animal

person MirekE    schedule 02.03.2015