質問
次のようなことを行う必要があるScalaコードを記述しようとしています:
class Test[Type] {
def main {
SomeFunc classOf[Type]
val testVal: Type = new Type()
}
}
それは失敗しています。私は明らかに、Scalaの汎用パラメーターについて何かを理解していません。明らかに、誤解は、C ++では、テンプレートは基本的に文字列置換のように機能するため、渡されるクラスにデフォルトコンストラクターがある限り、新しいType()は機能するということです。ただし、Scalaでは、型はさまざまな種類のオブジェクトです。
解決
ご指摘のとおり、C ++にはテンプレートがあります。要するに、C ++は<!> quot;と言います。Testがコンパイルされるように、すべてのタイプTのテストがあります。<!> quot;これにより、Tに暗黙的に制約を簡単に追加できますが、欠点は暗黙的であり、クラスのユーザーがコードを読まずに理解するのが難しい場合があります。
Scalaのパラメトリックポリモーフィズム(別名ジェネリック)は、ML、Haskell、Java、C#のように機能します。 Scalaでは、<!> quot; class Test [T] <!> quot;と書くと、あなたは<!> quot;と言っています、すべてのTには型Test [T] <!> quotが存在します。制約なし。それは正式に推論する方が簡単ですが、制約について明示する必要があることを意味します。たとえば、Scalaでは<!> quot; class Test [T <!> lt ;: Foo] <!> quot; TはFooのサブタイプでなければならないということです。
C#には、コンストラクターに関する制約をTに追加する方法がありますが、残念ながらScalaにはありません。
Scalaで問題を解決する方法はいくつかあります。 1つは型安全ですが、btはより冗長です。もう一方はタイプセーフではありません。
タイプセーフな方法は次のようになります
class Test[T](implicit val factory : () => T) {
val testVal = factory
}
その後、システムで役立つタイプのファクトリーのボディを持つことができます
object Factories {
implicit def listfact[X]() = List[X]()
implicit def setfact[X]() = Set[X]()
// etc
}
import Factories._
val t = new Test[Set[String]]
ライブラリのユーザーが独自のファクトリを必要とする場合、ファクトリオブジェクトと同等の独自のファクトリを追加できます。このソリューションの利点の1つは、引数のないコンストラクターがあるかどうかに関係なく、ファクトリーがあれば何でも使用できることです。
それほど安全ではない方法では、リフレクションと、型消去に関するJava制約を回避する方法であるマニフェストと呼ばれるScalaの機能を使用します
class Test[T](implicit m : Manifest[T]) {
val testVal = m.erasure.newInstance().asInstanceOf[T]
}
このバージョンでは、あなたはまだ書きます
class Foo
val t = new Test[Foo]
ただし、引数なしのコンストラクターがない場合は、静的型エラーの代わりにランタイム例外が発生します
scala> new Test[Set[String]]
java.lang.InstantiationException: scala.collection.immutable.Set
at java.lang.Class.newInstance0(Class.java:340)