[英]Path-dependent types and nested traits
Suppose I have some nested traits: 假设我有一些嵌套特征:
trait Foo { trait Bar }
And a couple of instances: 还有几个例子:
val myFoo = new Foo {}
val myBar = new myFoo.Bar {}
I can write the following, which look (at least at a glance) like they should do more or less the same thing: 我可以写下面的内容,看起来(至少一目了然)就像他们应该或多或少地做同样的事情:
def whatever1(foo: Foo)(bar: foo.Bar) = bar
def whatever2(foo: Foo): foo.Bar => foo.Bar = { bar => bar }
def whatever3(foo: Foo) = new { def apply(bar: foo.Bar) = bar }
case class whatever4(foo: Foo) { def apply(bar: foo.Bar) = bar }
case class whatever5[F <: Foo](foo: F) { def apply(bar: foo.Bar) = bar }
Note that the last is inspired by the solution given here . 请注意,最后一个受到此处给出的解决方案的启发。
The first three work: 前三项工作:
scala> val sameBar1: myFoo.Bar = whatever1(myFoo)(myBar)
sameBar1: myFoo.Bar = $anon$1@522f63e7
scala> val sameBar2: myFoo.Bar = whatever2(myFoo)(myBar)
sameBar1: myFoo.Bar = $anon$1@522f63e7
scala> val sameBar3: myFoo.Bar = whatever3(myFoo)(myBar)
sameBar2: myFoo.Bar = $anon$1@522f63e7
But not the fourth or fifth: 但不是第四或第五:
scala> val sameBar4: myFoo.Bar = whatever4(myFoo)(myBar)
<console>:12: error: type mismatch;
found : myFoo.Bar
required: _1.foo.Bar where val _1: whatever4
val sameBar4: myFoo.Bar = whatever4(myFoo)(myBar)
^
Fair enough—we can't do the following, either, probably for similar reasons: 很公平 - 我们也不能做以下事情,可能是出于类似的原因:
scala> val myOof = myFoo
myOof: Foo = $anon$1@39e4ff0c
scala> val myOofBar: myOof.Bar = new myFoo.Bar {}
<console>:10: error: type mismatch;
found : myFoo.Bar
required: myOof.Bar
val myOofBar: myOof.Bar = new myFoo.Bar {}
^
And it's not a big deal, anyway, since we've got three working solutions. 无论如何,这不是什么大问题,因为我们有三个工作解决方案。
(I'll start by noting that while I first ran into the problem below while working with macros, and while my example here involves the reflection API, my question is not specific to macros or reflection.) (我首先要注意的是,虽然我在使用宏时遇到了下面的问题,而我的示例涉及反射API,但我的问题不是特定于宏或反射。)
Suppose that I'm working with the new reflection API and want to be able to write the following: 假设我正在使用新的反射API并希望能够编写以下内容:
applier[List[_]](Literal(Constant(42)), Literal(Constant(13)))
And have it mean something like "give me the abstract syntax tree for List(42, 13)
". 并且它意味着“给我List(42, 13)
的抽象语法树”。 This isn't too hard—I can just use the approach from whatever3
above: 这不是太难 - 我可以使用上述whatever3
方法:
trait ReflectionUtils {
import scala.reflect.api.Universe
def companionApplier(u: Universe) = new {
def apply[A: u.TypeTag](xs: u.Tree*): u.Tree = u.Apply(
u.Select(u.Ident(u.typeOf[A].typeSymbol.companionSymbol), "apply"),
xs.toList
)
}
}
And now I get the syntax I want in my macros (see my answer to this question for a more detailed and motivated example): 现在我在我的宏中得到了我想要的语法(请参阅我对这个问题的 回答 ,以获得更详细和更有动力的例子):
object MacroExample extends ReflectionUtils {
import scala.language.experimental.macros
import scala.language.reflectiveCalls
import scala.reflect.macros.Context
def threeOfThem(n: Int) = macro threeOfThem_impl
def threeOfThem_impl(c: Context)(n: c.Expr[Int]) = {
val applier = companionApplier(c.universe)
c.Expr[List[Int]](applier[List[_]](n.tree, n.tree, n.tree))
}
}
And everything works as intended. 一切都按预期工作。 I don't really like the "reflective access of structural type member" business, though. 不过,我并不喜欢“结构型会员的反思性访问”业务。 Unfortunately I can't use the whatever1
or whatever2
approaches here, since I can't fix the type parameter when I apply this thing to my universe. 不幸的是我不能在这里使用whatever1
或whatever2
方法,因为当我将这个东西应用到我的宇宙时我无法修复类型参数。 I'd love to be able to write the following: 我很乐意写下面的内容:
case class companionApplier(u: Universe) {
def apply[A: u.TypeTag](xs: u.Tree*): u.Tree = u.Apply(
u.Select(u.Ident(u.typeOf[A].typeSymbol.companionSymbol), "apply"),
xs.toList
)
}
But this of course runs me into the type mismatch problems we saw with whatever4
above. 但这当然让我陷入了我们用上述whatever4
看到的类型不匹配问题。
Is there some other trick I'm missing? 我还缺少其他一些技巧吗? Is it possible for me to get the syntax I want without using an anonymous class with a structural type member? 我可以在不使用具有结构类型成员的匿名类的情况下获得我想要的语法吗?
How about splitting the structural type out as an auxiliary type and then sprinkling a little of my solution from the list, 如何将结构类型拆分为辅助类型,然后从列表中提取一些我的解决方案,
scala> trait Foo { trait Bar }
defined trait Foo
scala> val myFoo = new Foo {} ; val myBar = new myFoo.Bar {}
myFoo: Foo = $anon$1@11247416
myBar: myFoo.Bar = $anon$2@70415924
scala> class Whatever6Aux[F <: Foo](val foo: F) { def apply(bar: foo.Bar) = bar }
defined class Whatever6Aux
scala> def whatever6(foo: Foo) = new Whatever6Aux[foo.type](foo)
whatever6: (foo: Foo)Whatever6Aux[foo.type]
scala> import scala.language.existentials
import scala.language.existentials
scala> whatever6(myFoo)(myBar)
res0: _1.foo.Bar forSome { val _1: Whatever6Aux[<refinement>.type] } = $anon$2@70415924
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.