通过方法上下文参数调用实例允许自定义错误消息,以声明方式使用 @implicitNotFound 注释参数,这需要一个literal字符串支持类型占位符。
import scala.annotation.implicitNotFound
inline def singleInhabitantOf[A](using @implicitNotFound("The received type ${A} is not a singleton") voA: ValueOf[A]): A =
voA.value
singleInhabitantOf[Option[Int]] // Compile error: The received type Option[Int] is not a singleton
如果使用
summonFrom
实现召唤,我们可以自定义错误消息,强制调用 error
方法,该方法也需要 literal 字符串,但 没有类型占位符支持。
import scala.compiletime.{summonFrom, error}
inline def singleInhabitantOf2[A]: A = summonFrom {
case voA: ValueOf[A] => voA.value
case _ => error("The received type ${A} is not a singleton")
}
singleInhabitantOf2[Option[Int]] // compiler error: The received type ${A} is not a singleton
除了使用宏之外,还有没有一种方法可以在主体中调用一个隐式实例(如
summonFrom
那样),该实例具有类型占位符支持,或者更好的是动态字符串插值?
许多标准内联方法实际上是作为宏或编译器内部实现的。
有
shapeless3.typeable.Typeable[A].describe
但它不是内联的,所以不能在 error
中使用。
我在标准库中找不到这个,但你可以定义自己的小宏并在普通内联方法中随处使用它
// different file
import scala.quoted.{Quotes, Type, Expr}
inline def typeOf[A]: String = ${typeOfImpl[A]}
def typeOfImpl[A: Type](using Quotes): Expr[String] = Expr(Type.show[A])
import scala.compiletime.{summonFrom, error}
inline def singleInhabitantOf2[A]: A = summonFrom {
case voA: ValueOf[A] => voA.value
case _ => error("The received type " + typeOf[A] + " is not a singleton")
}