Вы нужно: а) написать new Foo[T]()
вместо new Foo[Any]()
(легкого) б) передать в макро представление типа T
, а именно, значение типа AbsTypeTag[T]
, путем объявления параметра T
с использованием контекста, связанный: [T: c.AbsTypeTag]
.
Вот код, который я тестировал в Scala 2.10.0-M7. Редактировать. В 2.10.0-RC1 AbsTypeTag
был переименован в 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](""))
}
Обратите внимание, что если опустить параметр типа, вы получите странные ошибки:
scala> Creator.create[Int]("")
res2: Foo[Int] = [email protected]
scala> Creator.create("")
<console>:12: error: macro has not been expanded
Creator.create("")
^
You также написать:
(above I use a string argument, but in the final version I plan to use the companion object of class T as a marker to know the argument-type of a Function1[T,Unit])
но если я понял, это звучит неплохо. Вместо того, чтобы писать Creator.create[T](otherArgs)
, синтаксис вызова будет чем-то вроде Creator.create(T, otherArgs)
, а не большим преимуществом (если есть). Но вы даже не можете получить последний синтаксис: если class A
и object A
являются компаньонами, их типы не связаны: первый имеет тип A
, второй имеет тип A.type
, где A
является сопутствующим объектом, а не типом класса A
.
Update: как получить 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]())
}
}
1.) Я просил аргумент не вводить параметр ... 2.) 'Создатель«Foo»' или 'а Создатель У Foo' есть некоторое преимущество ... (с точки зрения DSL). 3.) классы и их спутники связаны, и в них есть функции для их решения в отражении api. – subsub
Я не понимаю вашу точку зрения 1). В остальном я уверен, что нет общего способа получить синтаксис 'Creator create Foo', а не для произвольного' Foo'. Связь между классом и его компаньоном не может быть использована посредством вывода типа. Я собираюсь опубликовать не общее решение отдельно. – Blaisorblade
В конце я добавил не общее решение в конец вышеприведенного сообщения. – Blaisorblade