Scala在方法中使用self的最佳实践

时间:2018-04-23 05:56:18

标签: scala

我在调用一个使用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

2 个答案:

答案 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