如何在Swift中多态转换为类类型?

时间:2017-01-12 15:06:10

标签: swift swift3

这里,layEgg()想要重用chickenFactory(Chicken.Type)。问题是layEgg返回Self?所以我得到了这个类型的实例或者没有。

但是,chickenFactory返回一个Chicken,需要将其转换为我的任何类型。

enum BiologicalGender : String {
    case male = "male"
    case female = "female"
}

class Chicken {
    let gender : BiologicalGender

    required init (_ gender : BiologicalGender) {
        self.gender = gender
    }

    class func chickenFactory(_ chickenType : Chicken.Type) -> Chicken {
        if (arc4random_uniform(2) == 0) {
            return chickenType.init(.male)
        } else {
            return chickenType.init(.female)
        }
    }

    func layEgg() -> Self? {
        if (self.gender == .female) {
            return Chicken.chickenFactory(type(of:self)) // need a cast here
        } else {
            return nil
        }
    }
}

如何进行多态转换?

3 个答案:

答案 0 :(得分:4)

问题在于chickenFactory(_:)表示它采用类型Chicken.Type作为参数并输出Chicken的实例。输出的实例不必是您传入的类型(例如,当您输入Chicken类型时,它可以输出ChickenSubclass.self的实例。

您想要的不是类型转换,而是说输出的实例与您输入的类型的相同类型。为了表达这一点,您可以使用通用占位符:

class func chickenFactory<T : Chicken>(_ chickenType : T.Type) -> T {
    if (arc4random_uniform(2) == 0) {
        return chickenType.init(.male)
    } else {
        return chickenType.init(.female)
    }
}

现在

func layEgg() -> Self? {
    if (self.gender == .female) {
        return Chicken.chickenFactory(type(of: self))
    } else {
        return nil
    }
}

编译得很好,因为编译器知道可以从返回type(of: self)的函数返回类型Self?的实例。

尽管如此,chickenFactory(_:)的类型参数似乎是多余的,您可以通过在静态范围内使用self来使用它所调用的类型:

class func chickenFactory() -> Self {
    if (arc4random_uniform(2) == 0) {
        return self.init(.male)
    } else {
        return self.init(.female)
    }
}

func layEgg() -> Self? {
    if (self.gender == .female) {
        return type(of: self).chickenFactory()
    } else {
        return nil
    }
}

答案 1 :(得分:1)

问题的另一个解决方案是这个。查看this answer

func layEgg() -> Self? {
    if (self.gender == .female) {
        return makeEgg()
    } else {
        return nil
    }
}

func makeEgg<T>()->T?{
    return Chicken.chickenFactory(type(of:self)) as? T
}

答案 2 :(得分:0)

这不一定会改进代码,但是这里有一个包含原始工厂的类函数,可以完成对很多人演示的自我投射。

还包括原始的,改进的通用chickenFactory()。

class Chicken {
    let gender : BiologicalGender

    required init (_ gender : BiologicalGender) {
        self.gender = gender
    }

    class func chickenFactory<T:Chicken>(_ chickenType : T.Type) -> T {
        if (arc4random_uniform(2) == 0) {
            return chickenType.init(.male)
        } else {
            return chickenType.init(.female)
        }
    }

    class func poorlyTypedChickenFactory(_ chickenType : Chicken.Type) -> Chicken {
        if (arc4random_uniform(2) == 0) {
            return chickenType.init(.male)
        } else {
            return chickenType.init(.female)
        }
    }

    private class func chickenFromPoorlyTypedFactory<T>(_ chickenType : Chicken.Type) -> T?
    {
        let chicken = poorlyTypedChickenFactory(chickenType) as? T
        return chicken
    }

    func layEgg() -> Self? {
        if (self.gender == .female) {
            return Chicken.chickenFromPoorlyTypedFactory(type(of:self))
        } else {
            return nil
        }
    }
}