请告诉我如何使下面的代码按预期工作。问题是Scala编译器不理解我的工厂正在返回一个具体的类,所以我的对象以后不能使用。 TypeTags或类型参数可以帮助吗?或者我是否需要以其他方式重构代码?我(显然)是Scala的新手。
trait Animal
trait DomesticatedAnimal extends Animal
trait Pet extends DomesticatedAnimal {var name: String = _}
class Wolf extends Animal
class Cow extends DomesticatedAnimal
class Dog extends Pet
object Animal {
def apply(aType: String) = {
aType match {
case "wolf" => new Wolf
case "cow" => new Cow
case "dog" => new Dog
}
}
}
def name(a: Pet, name: String) {
a.name = name
println(a +"'s name is: " + a.name)
}
val d = Animal("dog")
name(d, "fred")
最后一行代码失败,因为编译器认为d
是Animal
,而不是Dog
。
答案 0 :(得分:4)
您应该为apply
的每个子类而不是Animal
特征使用Animal
方法创建伴随对象。此外,像使用name
一样使用可变字段被认为是一种不好的做法。
答案 1 :(得分:0)
您可以这样做,而无需更改任何其他内容:
val d = Animal("dog").asInstanceOf[Dog] //> d : Test.Dog = Test$$anonfun$main$1$Dog$1@1030dda
name(d, "fred") //> Test$$anonfun$main$1$Dog$1@1030dda's name is: fred
但是,我认为这不是一个好主意......
答案 2 :(得分:0)
我不想听起来粗鲁,但编译器认为d
是Animal
是正确的,因为这是Animal.apply
方法返回的内容。
正如已经指出的那样,您可以使用显式强制类型强制执行d类型,但它不会是类型安全的。它将利用您对作为程序员的方法实现的了解,随着代码库的增长最终成为错误的来源,并且您可能以意想不到的方式更改以前的代码。
如果需要调用Pet
方法,那么最好使用创建Pet
对象的工厂方法,或者至少在进行类型转换之前检查对象类型,使用
if (d.isInstanceOf[Pet]) name(d.asInstanceOf[Pet], "Fred")
或者更好的是,使用模式匹配
val d = Animal("dog")
d match {
case p: Pet => name(p, "fred")
case _ =>
}