scala - 使用 StringContext 的通用字符串插值器

标签 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](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))
                                           ^

最佳答案

在我看来,最简单的方法是依赖良好的旧重载:只需为要处理的每种类型定义不同的重载即可。

现在当然存在具有相同签名的不同重载的问题,并且像在 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)

关于scala - 使用 StringContext 的通用字符串插值器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38243802/

相关文章:

scala - Coproduct 对 `sealed trait` 的好处?

rust - 仅当满足类型约束条件时才有条件地实现 Rust 特性

swift - 是否可以在字符串的插值中包含一个方法? ( swift )

javascript - 如何使用 ES6 模板文字定义 sessionStorage 键

python字符串插值

scala - 范围内变量的模式匹配 (Scala)

scala - `.get(“key” )` on a `选项[Map [String,String]]`如何工作

scala - 使用 Scala 切出一个大的 CSV 文件

C高效读取20000000行文件的方法

c++ - 是否可以编写 C++ 基类成员函数来实例化从中调用它的任何派生类?