【问题标题】:Casting a superclass as one of its subclasses将超类转换为其子类之一
【发布时间】:2017-06-12 06:59:11
【问题描述】:

我有一个接受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中使用name呢? (因为动物和人都可以有名字)
  • attacker1.name as! Person这个不对,看V.Khambirs' Ans
  • @giorashc 他们不能。它要么是名称,要么是物种。并且根据传递给函数的类,它需要知道要请求哪一个。

标签: swift xcode casting


【解决方案1】:

您应该创建所需类型的新变量并将参数放入此变量中。

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

这样,如果attacker1 是Person,你只需将这个值保存到att1 常量中,然后你可以使用这个常量作为Person 类型的实例。

【讨论】:

    【解决方案2】:

    虽然@V.Khambir 的代码有效并且可能是更好的解决方案,但它并没有指出您的代码存在问题。您正在尝试将.name 转换为Person.name 不是 attacker1 的属性,这就是您收到错误的原因。您想要做的是将attacker1 转换为Person,然后访问name 属性。

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

    【讨论】:

    • 由于这个答案更具体地解决了我的问题,因此我将其标记为正确。
    • 这不使用 Swift 最佳实践,因为您实际上进行了两次强制转换......一次在检查中,然后在您想要访问 name 属性时再次进行。此处使用 if-let 语法的另一个答案实际上是您应该标记的答案,因为强制转换只进行一次,然后您就有了一个子类类型的强类型变量,因此不需要进一步的强制转换。
    • 我完全同意你的看法!我也不喜欢我的代码示例,更喜欢 V.Khambir 的代码示例。这就是我写第一句话的原因。但是,我想指出 Marmelador 代码的问题。
    【解决方案3】:

    因为 Being 是一个基类,所以它不能访问任何子类属性。所以首先,你要检查attacker1和attacker2的类型。例如:如果attacker1 是Person 类型,那么您可以将它类型转换为Person 类型的实例,然后访问person 对象的属性。 注意:- 确保先检查类型,然后再输入类型,否则会崩溃。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-03
      • 1970-01-01
      • 1970-01-01
      • 2017-06-04
      • 2012-07-22
      相关资源
      最近更新 更多