将超类转换为其子类之一

3

我有一个函数,它接受一个 Being 类型的实例。 Being 有两个子类:PersonAnimal。我希望函数能够识别传递的是哪一个子类,并对每个子类特定的属性进行操作。

我以为这样可以:

func fight(attacker1: Being, attacker2: Being) -> String {
    if attacker1 is Person {
        let name1 = attacker1.name as! Person //Error: Value of type Being has no member name
    } else {
        print("Its not a person")
    }

但这样做不行。实现我想要的最顺畅/最短的方法是什么?

在这种情况下,为什么不在基类Being中使用名称?(因为动物和人都可以有名称) - giorashc
attacker1.name as! Person 这是错误的,看看 V.Khambirs' Ans - D4ttatraya
@giorashc 他们不能。它只能是名字或物种之一。并且根据传递给函数的类,它需要知道要请求哪一个。 - Marmelador
3个回答

6
你应该创建所需类型的新变量,并将你的参数放入该变量中。
func fight(attacker1: Being, attacker2: Being) -> String {
    if let att1 = attacker1 as? Person {
        let name1 = att1.name
    } else {
        print("Its not a person")
    }

这样,如果攻击者1是“人(Person)”,你只需将该值保存到att1常量中,然后以该常量作为“Person”类型的实例。


3

虽然@V.Khambir的代码可以工作并且可能是更好的解决方案,但它并没有指出你代码的问题。你试图将.name强制转换为Person.name不是attacker1的属性,这就是为什么你会得到错误。你想做的是将attacker1强制转换为Person,然后访问名称属性。

func fight(attacker1: Being, attacker2: Being) -> String {
    if attacker1 is Person {
        let name1 = (attacker1 as! Person).name
    } else {
        print("Its not a person")
    }

由于这个答案更加具体地回答了我的问题,所以我已经将它标记为正确。 - Marmelador
这不是最佳实践,因为你实际上做了两次类型转换...一次在检查中,另一次是当你想访问名称属性时。这里的另一个答案使用if-let语法是实际上应该标记的,因为只有一次转换,而且你还拥有了一个强类型变量,所以不需要进一步的转换。 - Mark A. Donohoe
我完全同意你的观点!我也不喜欢我的代码示例,更喜欢V.Khambir的代码示例。这就是为什么我写了第一句话。但是,我想指出Marmelador的代码存在的问题。 - Yannick

0

由于Being是一个基类,因此它将无法访问任何子类属性。因此,首先,您必须检查attacker1和attacker2的类型。例如:如果attacker1是Person类型,则可以将其强制转换为Person类型的实例,然后访问person对象的属性。 注意:一定要先检查类型,然后再进行类型转换,否则会崩溃。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接