【问题标题】:Scala resolving Class/Type at runtime + type class constraintScala在运行时解析类/类型+类型类约束
【发布时间】:2021-11-17 18:52:41
【问题描述】:

我有一个通用函数,它需要 T 类型的 HasMoveCapability 隐式实例(type class 模式)

  trait HasMoveCapability[T]

  def doLogic[T: TypeTag: HasMoveCapability](): Unit = println(typeTag[T].tpe)

然后我有这两个具有 HasMoveCapability[T] 隐式实例的类

  case class Bird()
  object Bird {
    implicit val hasMoveCapability = new HasMoveCapability[Bird]{}
  }
  case class Lion()
  object Lion {
    implicit val hasMoveCapability = new HasMoveCapability[Lion]{}
  }

我的问题如下: 我需要根据参数在 runtime 解析类型(Lion 或 Bird),并使用正确的类型调用函数 doLogic

我试过了

  val input: String = "bird" // known at runtime
  val resolvedType: TypeTag[_] = input match {
    case "bird" => typeTag[Bird]
    case "lion" => typeTag[Lion]
  }

  doLogic()(resolvedType) // doesn't compile 
// `Unspecified value parameters: hasMoveCapability$T$1: HasMoveCapability[NotInferredT]`

我想做的是这样的:

  val resolvedType: TypeTag[_: HasMoveCapability] = input match{...}

目前我使用的解决方法是在模式匹配中调用函数:

input match {
    case "bird" => doLogic[Bird]
    case "lion" => doLogic[Lion]
  }

但是由于具有许多功能,模式匹配变得重复且难以维护。

如果您有任何建议,我愿意更改设计:D

【问题讨论】:

  • “但是由于具有许多功能,模式匹配变得重复且难以维护”。我个人宁愿尝试解决这个问题,也许创建一个类似main 的函数来做所有事情,这样你就只在模式匹配中调用一个?或者,也许您可​​以创建一个包含您需要的所有类型类的数据结构,然后从模式匹配中返回它。
  • 感谢您的评论 1- 在我的情况下,创建一个我从模式匹配中调用的类似 main 的函数实际上是不可能的,我有许多 main-functions/jobs 用于需要的不同用例使用相同的模式匹配 2- 我虽然要返回所有类型类,但这也不理想,因为我的模式匹配中有很多条目,每次添加新的类型类时,我都需要更新所有条目的结构,而实例已经存在于相应的伴随对象中。
  • 我会保持模式匹配然后,您需要将运行时值映射到编译时类型,而模式匹配是最简单/最自然的方法。如果并非所有案例都具有相同的逻辑,这似乎也是进行该匹配的一个很好的理由,并非所有重复都是不好的,在这种情况下,案例的重复似乎只会让您在未来进行更改的清晰性和简单性。

标签: scala functional-programming typeclass


【解决方案1】:

您应该更好地描述您的问题。目前您的类型类 HasMoveCapability 似乎没有做任何有用的事情。目前你所做的似乎很难将字符串"bird" 转换为"Bird""lion" 转换为"Lion"

如果你控制doLogic的代码,你似乎不需要TypeTagTypeTag / ClassTag 是一种将信息从编译时持续到运行时的方法。你似乎在做相反的事情。

类型类/隐式在编译时解析。您无法在编译时根据运行时信息解决某些问题(没有时间机器将您从未来(即运行时)带到过去(即编译时)。很可能您需要普通的模式匹配而不是类型类(TypeTagHasMoveCapability)。

原则上您可以在运行时运行编译器,然后您将在运行时拥有新的编译时间,并且您将能够推断类型、解析隐式等。

import scala.tools.reflect.ToolBox
import scala.reflect.runtime.currentMirror
import scala.reflect.runtime.universe.{TypeTag, typeTag}

object App {    
  trait HasMoveCapability[T]

  def doLogic[T: TypeTag: HasMoveCapability](): Unit = println(typeTag[T].tpe)

  case class Bird()
  object Bird {
    implicit val hasMoveCapability = new HasMoveCapability[Bird]{}
  }
  case class Lion()
  object Lion {
    implicit val hasMoveCapability = new HasMoveCapability[Lion]{}
  }

  val input: String = "bird" // known at runtime

  val tb = currentMirror.mkToolBox()
  tb.eval(tb.parse(s"import App._; doLogic[${input.capitalize}]")) //App.Bird

  def main(args: Array[String]): Unit = ()
}

scala get generic type by class

【讨论】:

    猜你喜欢
    • 2011-01-17
    • 2017-01-08
    • 1970-01-01
    • 2020-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多