2

特性で定義された抽象値フィールドがあるとします。

trait Base {
  val toBeOverride: String
}

case class Impl(other:Int) extends Base {
  override val toBeOverride = "some value"
}

toBeOverride次のように、値をオーバーライドするだけで複製されたインスタンスを簡単に取得できる関数を作成するにはどうすればよいですか。

// copy only available to case class instance
// v does not have method 'copy'
def overrideBaseValue[T <: Base](v: Base) = 
    v.copy(toBeOverride = "prefix" + v.toBeOverride) 

?

編集

Trait@som-snytt、 aが an と同じではないのと同じように、これは重複しているとは思いませんAbstract Class。そして、その質問の答えは私を満足させません。以下を参照してください。

@Blaisorblade、はい、それは問題です。各サブ ケース クラスのインスタンスでは、toBeOverrideフィールドは同じであるため、コンストラクターには表示されません。

今のところ、すべての提案はcopy、各 (!) サブケース クラスでカスタマイズされたメソッドを定義することですが、私の意見では、それは醜く、言語の無能さを示しています。

4

3 に答える 3

1

ここでは 2 つのメカニズムを説明します。

近い将来、無名サブクラスを生成できるマクロを作成できるようになる予定ですが、それまでは、この型クラスは難しくないと思います。

ここでダイナミックにタイヤを蹴るだけです。

import scala.language.dynamics
import scala.reflect._
import scala.reflect.runtime.{ currentMirror => cm }
import scala.reflect.runtime.universe._

trait Base {
  def m: String
}
case class Impl(p: Int) extends Base {
  override val m = "some value"
}

trait Basic extends Dynamic {
  protected def m: String
  def selectDynamic(f: String): Any =
    if ("m" == f) m else reflecting(this, f)
  protected def reflecting(b: Basic, f: String) = {
    val im = cm.reflect(b)
    val member = im.symbol.typeSignature member newTermName(f)
    require(member != NoSymbol, s"No such member $f")
    (im reflectMethod member.asMethod)()
  }
}
case class Implic(p: Int) extends Basic {
  override protected val m = "some value"
}

object Test extends App {

  implicit class Copy[A <: Base](val b: A) {
    def overriding(overm: String): A = (b match {
      case impl: Impl => new Impl(impl.p) { override val m = overm }
      case b: Base    => new Base { override val m = overm }
    }).asInstanceOf[A]
  }
  implicit class Proxy[A <: Basic : ClassTag](val b: A) {
    def proximately(overm: String): Basic = new Basic {
      override val m = overm
      override def selectDynamic(f: String): Any =
        if ("m" == f) overm else reflecting(b, f)
      override def toString = b.toString
    }
  }

  // asked for this
  //def overriding[T <: Base](v: Base) = v.copy(m = "prefix" + v.m)

  /* want something like this
  def overriding[T <: Base](v: Base) = new Impl(v.p) {
    override val m = "some value"
  } */

  val a = Impl(5)
  val b = a overriding "bee good"
  Console println s"$a with ${a.m} ~> $b with ${b.m}"
  // or
  val c = Implic(7)
  val d = c proximately "dynomite"
  Console println s"$c with ${c.m} ~> $d with ${d.m}"
}
于 2012-12-10T07:55:37.523 に答える
1

最も簡単な解決策は、必要なメソッドを Base に追加することです。

trait Base {
  val toBeOverride: String
  def copyBase(newToBeOverridden: String): Base
}

case class Impl(other:Int, override val toBeOverride: String = "some value") extends Base {
  def copyBase(newToBeOverridden: String) = copy(toBeOverride = newToBeOverridden)
}

Implこれにより、 の値を指定しながらのインスタンスを直接作成することもできますtoBeOverride(これは不可能でした)。唯一の欠点は、Impl を使用したパターン マッチで構文を変更する必要があることです。問題がある場合は、質問を更新してコメントを追加してください。

ところで、(あなたの例のように)プレフィックスを追加したいだけなら、それは問題ありません:

case class Impl(other:Int, override val toBeOverride: String = "some value") extends Base {
  def copyBase(newToBeOverridden: String) = copy(toBeOverride = toBeOverride + newToBeOverridden)
}
于 2012-12-09T22:57:09.480 に答える
0

トレイトはコピー メソッドを自動的に取得しないため、Base代わりにケース クラスを使用してみてください。

  case class Base(toBeOverride: String)

  case class Impl(other: Int, someVal: String = "some value") extends Base(someVal)

  def overrideBaseValue[T <: Base](v: Base) =
      v.copy(toBeOverride = "prefix" + v.toBeOverride)

ただし、遭遇する問題copyは、のインスタンスを返すことであり、それを元のクラスBaseに戻すことはできないと思います。Implたとえば、これはコンパイルされません:

  def overrideBaseValue[T <: Base](v: T): T =
      v.copy(toBeOverride = "prefix" + v.toBeOverride)
于 2012-12-09T17:59:56.127 に答える