【问题标题】:Instantiating a class's subtype in the companion object's apply method in Scala在 Scala 的伴生对象的 apply 方法中实例化类的子类型
【发布时间】:2014-11-06 04:11:31
【问题描述】:

我一直在尝试使用伴随对象来实例化一个类的子类型之一。在编译时不知道将实例化哪个子类。这与从第 127 页开始的Scala 编程 中的示例非常相似。我在这里设计了一个示例:

import scala.reflect.runtime.universe._


abstract class Animal
class Dog extends Animal { def bark = "woof" }
class Cat extends Animal { def meow = "meow" }

object Animal {
  def apply(specify: String): Option[Animal] = {
    specify match {
      case "dog" => Some(new Dog)
      case "cat" => Some(new Cat)
      case _     => None
    }
  }
}

object Test extends App {
  def getType[T: TypeTag](obj: T) = typeOf[T]

  var dog = Animal("dog")
  println(getType(dog))
}

这个程序打印出scala.Option[Animal]。我希望它能打印出scala.Option[Dog]。此外,如果我尝试将行 println(dog.bark) 添加到 Test 对象的末尾,则编译失败。这根本不可能吗?

我一直在研究 Scala 反射文档,但它似乎非常密集和困难。此外,这似乎正是 Programming Scala 示例的工作原理,所以我无法想象我在这里做错了什么。


编辑:这个版本没有反射,只是由于类型错误而引发编译时错误。

abstract class Animal
class Dog extends Animal { def bark = "woof" }
class Cat extends Animal { def meow = "meow" }

object Animal {
  def apply(specify: String): Option[Animal] = {
    specify match {
      case "dog" => Some(new Dog)
      case "cat" => Some(new Cat)
      case _     => None
    }
  }
}

object Test extends App {
  var dog = Animal("dog")
  println(dog.get.bark)
}

// $ scalac test.scala
// test.scala:17: error: value bark is not a member of Animal
//   println(dog.get.bark)
//                   ^
// one error found

编辑:显然这需要模式匹配才能解决。这是一个工作示例,稍微简化了一些。

abstract class Animal
class Dog extends Animal { def bark = "woof" }
class Cat extends Animal { def meow = "meow" }

object Animal {
  def apply(specify: String): Animal = {
    specify match {
      case "dog" => new Dog
      case "cat" => new Cat
    }
  }
}

object Test extends App {
  val dog = Animal("dog")
  dog match {
    case d: Dog => println(d.bark)
    case _      =>
  }
}

【问题讨论】:

  • 这会产生编译错误:` 错误:没有可用于 Option[this.Animal] 的 TypeTag `。您使用的是哪个版本的 Scala?
  • 我安装了 2.11.4。我将修改添加一个不使用反射的版本(并且由于类型问题而无法编译)。

标签: scala apply factory-pattern subtype companion-object


【解决方案1】:

这是不可能的。

在第二个例子中,Animal.apply 总是返回 Option[Animal],因为那是它的类型签名。

你的object Test真的是在说,扩大了一点:

object Test extends App {
  var dog: Option[Animal] = Animal.apply("dog")
  println(dog.get.bark)
}

编译器可能能够在编译时判断它可能是Option[Dog],但语言的语义不允许这样做:语法必须要复杂得多才能能够封装这些知识。

【讨论】:

  • 听起来你在说,不可能。
  • 是的,这是不可能的。
  • 您可以使用matchisInstanceOf 在运行时检查其类型...但我认为这不是您想要的。
  • 我很想知道这与 Programming Scala 中的示例有什么根本不同。
  • 在 p 周围的例子中。 127,本书不会调用仅在子类中的方法,而无需先使用match 来检查类型(如第 128 页的规范示例中所示)。
猜你喜欢
  • 1970-01-01
  • 2022-08-19
  • 1970-01-01
  • 1970-01-01
  • 2023-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多