(1)尝试引入类型类IsFoo
trait Foo[A]
trait IsFoo[A] {
def value(): Boolean
}
trait LowPriorityIsFoo {
implicit def noFoo[A]: IsFoo[A] = () => false
}
object IsFoo extends LowPriorityIsFoo {
implicit def existsFoo[A](implicit foo: Foo[A]): IsFoo[A] = () => true
}
def isFoo[A](implicit isFooInst: IsFoo[A]): Boolean = isFooInst.value()
测试:
implicit val intFoo: Foo[Int] = null
isFoo[Int] // true
isFoo[String] // false
实际上,我猜我的 isFoo 只是 @LuisMiguelMejíaSuárez 的一个更复杂的变体
def isFoo[A](implicit ev: Foo[A] = null): Boolean = Option(ev).isDefined
(2) 您想通过继承/子类型多态性来定义Marshaller 的行为。在 JVM 语言中,它是动态调度的(最近,在运行时)。现在您想将它与静态分派的隐式/类型类 (Foo)/临时多态性(早期,在编译时)混合。您必须使用一些运行时工具,例如运行时反射(将有关 Node 的编译时信息保存到运行时,使用 TypeTags)、运行时编译。
import scala.reflect.runtime.universe.{TypeTag, typeOf, Quasiquote}
import scala.reflect.runtime.currentMirror
import scala.tools.reflect.ToolBox
val tb = currentMirror.mkToolBox()
trait Foo[A]
trait Marshaller[Node] {
def isFoo(n: Node): Boolean
}
class MyMarshaller[Node: TypeTag] extends Marshaller[Node] {
// override def isFoo(n: Node): Boolean =
// tb.inferImplicitValue(
// tb.typecheck(tq"Foo[${typeOf[Node]}]", mode = tb.TYPEmode
// ).tpe).nonEmpty
override def isFoo(n: Node): Boolean =
util.Try(tb.compile(q"implicitly[Foo[${typeOf[Node]}]]")).isSuccess
}
implicit val intFoo: Foo[Int] = null
new MyMarshaller[Int].isFoo(1) //true
new MyMarshaller[String].isFoo("a") //false
Scala resolving Class/Type at runtime + type class constraint
Is there anyway, in Scala, to get the Singleton type of something from the more general type?
Load Dataset from Dynamically generated Case Class
Implicit resolution fail in reflection with ToolBox
In scala 2 or 3, is it possible to debug implicit resolution process in runtime?
(3) 如果您只想检查 Node 是否为 Map[String, _],那么只需运行时反射就足够了
import scala.reflect.runtime.universe.{TypeTag, typeOf}
trait Marshaller[Node] {
def isFoo(n: Node): Boolean
}
class MyMarshaller[Node: TypeTag] extends Marshaller[Node] {
override def isFoo(n: Node): Boolean = typeOf[Node] <:< typeOf[Map[String, _]]
}
new MyMarshaller[Map[String, _]].isFoo(Map()) //true
new MyMarshaller[Int].isFoo(1) //false
另见Typeable
import shapeless.Typeable
trait Marshaller[Node] {
def isFoo(n: Node): Boolean
}
class MyMarshaller[Node] extends Marshaller[Node] {
override def isFoo(n: Node): Boolean = Typeable[Map[String, _]].cast(n).isDefined
}
new MyMarshaller[Map[String, _]].isFoo(Map()) //true
new MyMarshaller[Int].isFoo(1) //false
(4) 在 Scala 3 中,您可以使用 pattern matching by implicits
import scala.compiletime.summonFrom
trait Foo[A]
trait Marshaller[Node] {
def isFoo(n: Node): Boolean
}
class MyMarshaller[Node] extends Marshaller[Node] {
override inline def isFoo(n: Node): Boolean = summonFrom {
case given Foo[Node] => true
case _ => false
}
}
given Foo[Int] with {}
new MyMarshaller[Int].isFoo(1) //true
new MyMarshaller[String].isFoo("a") //false
(5) 实际上,我想最简单的方法是将隐式参数从方法移动到类
trait Foo[A]
trait IsFoo[A] {
def value(): Boolean
}
trait LowPriorityIsFoo {
implicit def noFoo[A]: IsFoo[A] = () => false
}
object IsFoo extends LowPriorityIsFoo {
implicit def existsFoo[A: Foo]: IsFoo[A] = () => true
}
trait Marshaller[Node] {
def isFoo(n: Node): Boolean
}
class MyMarshaller[Node: IsFoo] extends Marshaller[Node] {
// ^^^^^ HERE
override def isFoo(n: Node): Boolean = implicitly[IsFoo[Node]].value()
}
implicit val intFoo: Foo[Int] = null
new MyMarshaller[Int].isFoo(1) //true
new MyMarshaller[String].isFoo("a") //false
(6) @LuisMiguelMejíaSuárez的默认隐式思想也可以在这种情况下使用
trait Foo[A]
trait Marshaller[Node] {
def isFoo(n: Node): Boolean
}
class MyMarshaller[Node](implicit ev: Foo[Node] = null) extends Marshaller[Node] {
override def isFoo(n: Node): Boolean = Option(ev).isDefined
}
implicit val intFoo: Foo[Int] = new Foo[Int] {}
new MyMarshaller[Int].isFoo(1) //true
new MyMarshaller[String].isFoo("a") //false