Scala 使用StringContext的通用字符串插值器
我正在尝试创建一些简单的自定义字符串插值器,只要我不尝试使用类型参数,我就成功了Scala 使用StringContext的通用字符串插值器,scala,generic-programming,string-interpolation,scala-implicits,Scala,Generic Programming,String Interpolation,Scala Implicits,我正在尝试创建一些简单的自定义字符串插值器,只要我不尝试使用类型参数,我就成功了 import scala.concurrent.Future object StringImplicits { implicit class FailureStringContext (val sc : StringContext) extends AnyVal { // This WORKS, but it's specific to Future :( def fail[T](ar
import scala.concurrent.Future
object StringImplicits {
implicit class FailureStringContext (val sc : StringContext) extends AnyVal {
// This WORKS, but it's specific to Future :(
def fail[T](args : Any*): Future[T] = {
val orig = sc.s (args : _*)
Future.exception[T](new Exception(orig))
}
// I want this to work for Option,Try,Future!!
def fail[M,T](args:Any*): M[T] = {
val orig = sc.s (args : _*)
// Obviously does not work..
M match {
case Future => Future.exception(new Exception(orig))
case Option => None
case Try => Failure(new Exception(orig))
case _ => ???
}
}
}
}
我能让它工作吗?我不能使用参数多态性,因为我不是定义这三种类型的人
伪代码模式匹配在类型级别的等价物是什么
最新尝试
我最近的尝试是隐式使用,但我没有这样的隐式!实际上,我有兴趣掌握编译器希望我根据类型推断返回的类型
def fail[T, M[T]](args:Any*): M[T] = {
val orig = sc.s(args: _*)
implicitly[M[T]] match {
case _:Future[T] => Future.exception(new Exception(orig))
case _ => ???
}
}
<console>:18: error: could not find implicit value for parameter e: M[T]
implicitly[M[T]] match {
^
<console>:19: error: value exception is not a member of object scala.concurrent.Future
case _: Future[T] => Future.exception(new Exception(orig))
^
def fail[T,M[T]](参数:Any*):M[T]={
val orig=sc.s(参数:*)
隐式[M[T]]匹配{
案例u10;:Future[T]=>Future.exception(新异常(orig))
案例=>???
}
}
:18:错误:找不到参数e:M[T]的隐式值
隐式[M[T]]匹配{
^
:19:错误:值异常不是对象scala.concurrent.Future的成员
案例u10;:Future[T]=>Future.exception(新异常(orig))
^
在我看来,最简单的方法是依靠好的重载:只需为要处理的每种类型定义不同的重载即可
当然,有一个问题是使用相同的签名使用不同的重载,在scala中,您可以像往常一样使用技巧来解决这些问题。这里我们将添加伪隐式参数,以强制每个重载具有不同的签名。这并不漂亮,但在这种情况下它可以工作,并且已经足够了
import scala.concurrent.Future
import scala.util.{Try, Failure}
implicit class FailureStringContext (val sc : StringContext) extends AnyVal {
def fail[T](args : Any*): Future[T] = {
Future.failed[T](new Exception(sc.s (args : _*)))
}
def fail[T](args : Any*)(implicit dummy: DummyImplicit): Option[T] = {
Option.empty[T]
}
def fail[T](args : Any*)(implicit dummy: DummyImplicit, dummy2: DummyImplicit): Try[T] = {
Failure[T](new Exception(sc.s (args : _*)))
}
}
和多田:
scala> fail"oops": Option[String]
res6: Option[String] = None
scala> fail"oops": Future[String]
res7: scala.concurrent.Future[String] = scala.concurrent.impl.Promise$KeptPromise@6fc1a8f6
scala> fail"oops": Try[String]
res8: scala.util.Try[String] = Failure(java.lang.Exception: oops)
请参阅:
def-test[A,B](A:Any):A[B]=?
=>编译错误:A
不接受类型参数。A
是泛型的,可以是Int
例如。Int[String]不存在。因此编译器总是会抱怨。因此,也许我需要告诉编译器我希望A是更高的类型?如何?def失败[T,M[T](…)
部分地解决了您的问题。但我不知道您将如何在调用站点指定M。您是否希望编译器根据所需的返回类型推断M的用途?@sscarduzio:很抱歉打断您的问题,但这似乎是一个糟糕的主意。是否有令人信服的理由让您觉得需要保存一些按键(交易Future.failed
,带有一个不太明显的fail“…”
,使其具有多态性,并且在选项的情况下,字符串被悄悄忽略)?或者仅仅是为了好玩?不管怎样,如果你觉得需要,那么好的旧重载有什么错?为你想要支持的每种类型定义一个不同的重载似乎是最明智的解决方案。公平地说,这是一种完全合理的学习方法(我也倾向于滥用特性,只是为了好玩和探索)。只是想确保你不是真的认为这是一个生产代码的好主意。整洁,但在我看来,在调用它时需要指定类型,而不是从一开始就消除了重载的问题。只需将fail
函数称为不同的名称-failOption
等。没有办法解决它,你可以ave以某种方式给出所需类型。但与任何类型归属一样,仅当您尚未处于已知所需类型的上下文中时才有必要这样做。如果您使用fail
作为具有显式返回类型的方法的返回值)举例来说,或者作为参数传递给非泛型方法,无需再指定类型。令人钦佩的是,只指定您想要的类型比执行手动名称修改更简洁…您使用dummy
来允许重载,对吗?这是一个很好的技巧:)直到“DummyImplicit”