1

いくつかの関数に基づく型でクラスを宣言しようとしています。

class A{
  def getC = 10
}

class B {
  def getC = 100
  def getB = 9
}


def readC[T <: {def getC():Int}](obj:T) = {
  obj.getC()
}

val a = new A()
val b  = new B()

readC(a)
readC(b) 

readC は A と B の両方で機能するはずです。また、A と B のクラスを変更できないため、ここでは特性ベースのソリューションは機能しません。

また、それを行うより良い方法はありますか?

4

2 に答える 2

4

あなたがやろうとしていることは構造型付けと呼ばれ、Scala でサポートされています。実際のクラスがないため、JVM での実装はリフレクションに依存する必要がgetCあるため、特性ベースのソリューションと比較して呼び出しがかなり遅くなります。このような状況での呼び出しはリフレクション呼び出しと呼ばれ、自分が何をしているのかを知っていることを認識しgetCない限り、コンパイラは実際に警告を発します。import scala.language.reflectiveCalls

私の意見では、通常型クラスと呼ばれるものに依存する、より洗練されたソリューションがあります。HasC「持つ」とはどういう意味かを定義するトレイトを定義し、 とCの両方の実装を提供します。はあなたの特徴であるため、との実装を制御できなくても実行できます。次に、暗黙的に使用可能な任意の型を取る has を定義します。Scala はコンテキスト境界を通じてこれをサポートします: . ABHasCABreadCTHasC[T]def readC[T: HasC]

これが実際の例です:

class A {
  def getCFromA: Int = 10
}

class B {
  def getCFromB: Int = 100
}

trait HasC[T] {
  def c(t: T): Int
}

object HasC {
  implicit object AHasC extends HasC[A] {
    def c(a: A): Int = a.getCFromA
  }
  implicit object BHasC extends HasC[B] {
    def c(b: B): Int = b.getCFromB
  }
} 

def readC[T : HasC](t: T): Int = implicitly[HasC[T]].c(t)

val a = new A()
val b  = new B()

readC(a)
readC(b)

この行

def readC[T : HasC](t: T): Int = implicitly[HasC[T]].c(t)

は、(ほぼ間違いなく)より優れた書き方です

def readC[T](t: T)(implicit hasC: HasC[T]): Int = hasC.c(t)

と の両方でgetC定義する必要がないため、これはより一般的であることに注意してください。そのため、メソッドの名前をおよびに変更しました。ABgetCFromAgetCFromB

型クラスは、Scala の多くの関数型プログラミングの基礎であり、同様の概念が Haskell、Rust (トレイト)、Swift (プロトコル) などの他の最新の言語で利用できます。

于 2019-08-23T11:53:01.403 に答える