↑ みたいに共通の options を持つ case class 郡があって、それぞれが copy を返す setter を持ってる。
けど全く DRY じゃない。
↓ みたいに trait で括りだしたいけど copy メソッドがそれぞれ違うため共通化できない。
なんか DRY にする方法はないものか?
case class User(id: String, name: String, options: Seq[String]) { | |
def options(os: String*): User = copy(options = options ++ os) | |
} | |
case class Group(id: String, name: String, subgroups: Seq[Group], options: Seq[String]) { | |
def options(os: String*): Group = copy(options = options ++ os) | |
} |
trait Optional { | |
def options(os: String*): this.type = ... | |
} | |
case class User(id: String, name: String, options: Seq[String]) extends Optional | |
case class Group(id: String, name: String, subgroups: Seq[Group], options: Seq[String]) extends Optional |
reflection のコストを許容できるなら全然アリっすね!
ありがとうございます。
this.type 使えば T は要らないかもです。
trait Optional extends Cloneable { self: {val options: Seq[String]} =>
override def clone(): this.type = super.clone().asInstanceOf[this.type]
def options(args: String*): this.type = {
val o = clone
val f = o.getClass.getDeclaredField("options")
f.setAccessible(true)
f.set(o, options ++ args)
o
}
}
case class User(id: String, name: String, options: Seq[String]) extends Optional
case class Group(id: String, name: String, subgroups: Seq[Group], options: Seq[String]) extends Optional
以前にcopyメソッドをtraitにしようと試行錯誤したことがありますが,
macro以外ではcopyメソッドを使わずにリフレクションを使うしかないという結論に達しました.
素直に個別実装した方がよいと思いますが,無理やりやると以下のような感じでいけるかと.