次のことを行う必要があります: a) (簡単な)new Foo[T]()
の代わりに書き込みますnew Foo[Any]()
b) マクロに type の表現T
、つまり type の値を渡しAbsTypeTag[T]
ます。T
[T: c.AbsTypeTag]
Scala 2.10.0-M7 でテストしたコードを次に示します。編集します。2.10.0-RC1AbsTypeTag
では、名前が に変更されましたWeakTypeTag
。マクロと型タグに関する他のすべては同じままです。
Creator.scala:
import language.experimental.macros
import reflect.macros.Context
class Foo[T]
object Creator {
def create[T](s: String): Foo[T] = macro createImpl[T]
def createImpl[T: c.AbsTypeTag](c: Context)(s: c.Expr[String]): c.Expr[Foo[T]] = {
import c.universe._
reify(new Foo[T]())
}
}
MacroClient.scala:
object Main extends App {
println (Creator.create[Int](""))
}
type パラメータを省略すると、奇妙なエラーが発生することに注意してください。
scala> Creator.create[Int]("")
res2: Foo[Int] = Foo@4888884e
scala> Creator.create("")
<console>:12: error: macro has not been expanded
Creator.create("")
^
また、次のようにも書きます。
(上記では文字列引数を使用していますが、最終バージョンでは、クラス T のコンパニオン オブジェクトをマーカーとして使用して、Function1[T,Unit] の引数の型を知る予定です)
しかし、私がそれを正しければ、これは悪い考えのように聞こえます。を書く代わりにCreator.create[T](otherArgs)
、呼び出し構文は のようなものになりCreator.create(T, otherArgs)
、大きな利点はありません (もしあれば)。しかし、後者の構文を取得することさえできません:class A
とobject A
がコンパニオンの場合、それらの型は関係ありません: 最初は typeA
を持ち、2 番目は type を持ちA.type
、A
はコンパニオン オブジェクトであり、 class のタイプではありませんA
。
更新:を制御できる場合に、Creator create Foo
構文を機能させ、 のインスタンスを返す方法。への型引数について質問しているので、型引数について質問していると思います。これは、静的な戻り値の型を でなく にしたい場合にのみ意味があります。それ以外の場合は、質問を明確にする必要があります。Foo
Foo
Any
reify
Creator.create
T
Any
ここでの問題は、マクロとはほとんど関係ありません。Creator create Foo
はオブジェクトFoo
をCreator.create
に渡します。その宣言は、与えられFoo.type
た に型式Foo
を介して型を表現する必要があります。Scala の型式は非常に制限されています。たとえば、リフレクションを使用することはできません。ただし、型を指定すると、その型メンバーを選択できます。
trait Companion[Class]
//How to declare a companion
class Foo
object Foo extends Companion[Foo]
/*I'm cheating: an implementation of Companion does not need to be a true Companion. You can add documentation to explain how Companion is supposed to be used. */
object Bar extends Companion[Foo]
//But this is also useful - you can't create your own companion objects for pre-existing types, but you can still create the right instances of Companion:
object pInt extends Companion[Int]
object Creator {
//T with Companion[S] is needed to workaround a type inference bug (SI-5298) and allow S to be correctly inferred.
def create[S, T <: Companion[S]](obj: T with Companion[S]): S = ???
}
コンパニオン オブジェクトを変更する必要があるため、これには制限がありますが、これ以上のことはできないと確信しています。型式S
(の戻り値の型を宣言するときに の代わりに使用できるものcreate
) で、コンパニオン オブジェクトから関連するクラス型に一般的に取得する方法がわかりません。
さて、マクロを使用するように上記を変更するのは簡単です:
import language.experimental.macros
import reflect.macros.Context
class Foo[T]
object Creator {
//T with Companion[S] is needed to workaround a type inference bug (SI-5298) and allow S to be correctly inferred.
def create[S, T <: Companion[S]](obj: T with Companion[S]): Foo[S] = macro createImpl[S, T]
def createImpl[S: c.AbsTypeTag, T <: Companion[S]: c.AbsTypeTag](c: Context)(obj: c.Expr[T with Companion[S]]): c.Expr[Foo[S]] = {
import c.universe._
reify(new Foo[S]())
}
}