【问题标题】:Method parametrized by a class' method return type由类的方法返回类型参数化的方法
【发布时间】:2015-04-01 04:36:48
【问题描述】:

是否可以获取未初始化案例类方法的返回类型?我想创建一个像这样工作的包装器:

abstract class Node[L, R]{
    def call(args: L): R
}
case class Kls(arg1: Int, arg2: Int) {
    def apply() = arg1 + arg2
}

object Node {
def apply[L <: { def apply(): R }, R](implicit lgen: LabelledGeneric[L]): Node[lgen.Repr, R] = {
  new Node[lgen.Repr, R] {
    def call(args: lgen.Repr): R = {
      lgen.from(args).apply()
    }
  }
}
}

val n = Node[Kls] // does not compile - missing type param R
n.call(arg1 :: arg2 :: HNil) //should have the right return type

或者,是否有 FnTo标签产品?我需要创建什么样的宏符?

【问题讨论】:

  • 如果没有 NodeKls 的定义,很难判断这里发生了什么。 “未初始化”是什么意思?
  • 为问题添加了定义。未初始化是指 Node.apply 仅传递一个类型参数,而不是实际的 Kls 实例

标签: scala shapeless


【解决方案1】:

也许我理解错了,但我认为你根本不需要L

case class Kls(arg1: Int, arg2: Int) {
  def apply() = arg1 + arg2
}

abstract class Node[L, R]{
  def call(args: L): R
}

import shapeless._

object Node {
  def apply[R](implicit gen: LabelledGeneric[R]): Node[gen.Repr, R] =
    new Node[gen.Repr, R] {
      def call(args: gen.Repr): R = gen.from(args)
    }
}

然后:

import shapeless.syntax.singleton._

val n = Node[Kls]

val result = n.call('arg1 ->> 1 :: 'arg2 ->> 2 :: HNil)

result 将静态类型化为Kls。这是你要找的吗?

【讨论】:

  • 对我来说,R 类型应该是 OP 示例中的 Int,因为它应该是 Klsapply 方法的结果类型。
  • 哦,有道理。今晚我会更新答案,除非有人打败我。
【解决方案2】:

我已经用一个简单的宏解决了这个问题:

trait CallApply[C] {
  type Ret
  def apply(c: C): Ret
}

object CallApply {
  type Aux[C, R] = CallApply[C] { type Ret = R }

  implicit def materialize[C, R]: Aux[C, R] = macro CallApplyImpl.materialize[C]
}

object CallApplyImpl {
  import scala.reflect.macros.whitebox

  def materialize[C: c.WeakTypeTag](c: whitebox.Context): c.Tree = {
    import c.universe._

    val C = weakTypeOf[C]
    val assignM = C.decls.collect {
      case sym: MethodSymbol if sym.name == TermName("apply") => sym
    }
    if (assignM.headOption.isEmpty) c.abort(c.enclosingPosition, "case class must define an apply() method")

    val R = assignM.head.returnType
    q"""new _root_.fwb.api.CallApply[$C] { type Ret = $R; def apply(c: $C) : $R = c.apply() }"""
  }
}

用法:

  object Node {
    def call[L](implicit lgen: LabelledGeneric[L], ev: CallApply[L]): Node[lgen.Repr, ev.Ret] = {
      new Node[lgen.Repr, ev.Ret] {
        def call(args: lgen.Repr): ev.Ret = {
          ev(lgen.from(args))
        }
      }
    }
  }

val n = Node[Kls] 按预期工作。但是,如果可能的话,很高兴看到没有元编程的解决方案。

【讨论】:

    猜你喜欢
    • 2012-10-31
    • 2015-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多