创建类型敏感函数而不更改父特征或案例类

bru*_*uno 2 extension-methods scala class implicit implicit-class

假设我有两个类PersonBusiness,它们由特质 扩展Entity

trait Entity
case class Person(name: String) extends Entity
case class Business(id: String) extends Entity
Run Code Online (Sandbox Code Playgroud)

假设我无法更改Entity,Person并且Business(它们位于不同的文件中并且不能更改),我如何定义一个函数,例如 a ,根据实体printEntity打印字段name或?id例如,给定Person和的实例Business,我该如何做这样的事情:

object Main extends App {
  val person1: Person = Person("Aaaa Bbbb")
  val business1: Business = Business("0001")
  
  // How can I do something like this?
  person1.printEntity // would call a function that executes println(id)
  business1.printEntity // would call a function that executes println(name)
}
Run Code Online (Sandbox Code Playgroud)

任何想法表示赞赏!抱歉,缺乏上下文,我仍在学习!

Aiv*_*ean 5

这是通过所谓的“扩展方法”完成的。在 scala 2 中,这是使用隐式包装类来实现的:

trait Entity
case class Person(name: String) extends Entity
case class Business(id: String) extends Entity

implicit class PersonWrapper(val p: Person) extends AnyVal {
  def printEntity(): Unit = {
    println(p.name)
  }
}

implicit class BusinessWrapper(val b: Business) extends AnyVal {
  def printEntity(): Unit = {
    println(b.id)
  }
}

val person1: Person = Person("Aaaa Bbbb")
val business1: Business = Business("0001")

person1.printEntity()
business1.printEntity()

// prints:
//Aaaa Bbbb
//0001
Run Code Online (Sandbox Code Playgroud)

注意,x.printEntity可以在没有括号的情况下调用,但是按照惯例,具有Unit结果类型和副作用的方法应该使用显式的空括号来调用。


UPD:正如 @DmytroMitin 指出的那样,您应该AnyVal. 这允许编译器避免在运行时实际分配包装类实例,从而提高性能。

  • @DmytroMitin,谢谢您的提醒,我已经更新了我的答案。 (2认同)
  • 这不应该添加到您的答案中(已经没问题了,我投了赞成票),但只是为了记录,在一些特殊情况下,普通类+隐式转换可能比相应的隐式类更好 https://stackoverflow.com/ questions/63964610/implicit-view-not-working-is-my-implicit-def-to-blame/ :) 我还没有检查当前的 Scala 2.13.6。当然通常情况并非如此。 (2认同)