我在调用一个使用self的方法时有一个案例。现在不确定在Scala中执行此操作的最佳实践。我已经创建了一个例子,说明我是怎么做的,只是想问这是最好的方法。
sealed trait Animal {
// match on self
final def speak(): Unit = {
this match {
case Cat(name) => println("spoken like a Cat named: " + name)
case Dog(name) => println("spoken like a Dog named: " + name)
case Pig(name) => println("spoken like a Pig named: " + name)
}
}
final def whoAmI(): Unit = {
this match {
case Cat(_) => println("I am a Cat")
case Dog(_) => println("I am a Dog")
case Pig(_) => println("Could be a Pig")
}
}
}
final case class Cat(name: String) extends Animal
final case class Dog(name: String) extends Animal
final case class Pig(name: String) extends Animal
答案 0 :(得分:4)
如果您的要求仅知道使用了哪种子类型,只需this.getClass()
即可以更简单的方式访问它:
sealed trait Animal {
val name: String
final def speak(): Unit =
println(s"spoken like a ${this.getClass.getSimpleName} named: ${name}")
final def whoAmI(): Unit =
println(s"I am a ${this.getClass.getSimpleName}")
}
如果所有实现子类型都以name
为特征,那么声明抽象val name: String
会很方便,这将允许访问speak()
中的字段。
对于这样的用例,匹配器不是最佳选择:对于每个实现子类型,您必须在匹配器中添加一个条目(可能变得难以维护)。我建议使用继承:如果你有一个在子类型之间有区别的行为,在trait中声明一个抽象方法,从中调用它,但它的实现应该保持在子类型级别。
答案 1 :(得分:1)
是的,您在this
上使用模式匹配是正确的。
由于您的层次结构是密封的,因此您不会考虑任何新类型 - 否则您应该拥有_ => ...
子句。
你可以更简单地表达你的第二个案例,因为你不关心参数,只关心类型。
final def whoAmI(): Unit = {
this match {
case _:Cat => println("I am a Cat")
case _:Dog => println("I am a Dog")
case _:Pig => println("Could be a Pig")
}
}
最后,this
总是指最里面的类型。对于嵌套的内部类,您可能希望使用别名,例如self
:
trait Tweeter {
this: self => // reassign this into self, so it can be accessed from an inner class