实例化一个类';伴随对象中的s子类型';s在Scala中的应用方法

实例化一个类';伴随对象中的s子类型';s在Scala中的应用方法,scala,apply,factory-pattern,subtype,companion-object,Scala,Apply,Factory Pattern,Subtype,Companion Object,我一直在尝试使用一个伴随对象来实例化一个类的子类型。编译时不知道将实例化哪个子类。这与从第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 Ani

我一直在尝试使用一个伴随对象来实例化一个类的子类型。编译时不知道将实例化哪个子类。这与从第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反射文档,但它似乎非常密集和困难。此外,这似乎正是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 _      =>
  }
}
这是不可能的

在第二个示例中,
Animal.apply
始终返回
Option[Animal]
,因为这是它的类型签名

你的
对象测试
实际上是说,扩展了一点:

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

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

这就产生了编译错误:`error:No TypeTag available for Option[This.Animal]`。您使用的是哪个版本的Scala?我已经安装了2.11.4。我将修改添加一个不使用反射的版本(并且由于类型问题而无法编译)。这听起来像是你在说,这不可能。是的,这是不可能的。你可以在运行时执行
匹配
isInstanceOf
来检查它的类型。。。但这不是你想要的,我想。我想知道这和Scala编程的例子有什么根本不同。127,本书不会调用仅在子类中的方法,而不会首先使用
match
检查类型(如第128页的规范示例)。