1

在下面的示例中,我试图声明一个类WrappedString,它只是包装了一个String[1]。我希望能够将此类实例与+运算符连接起来,并在必要时将普通String实例自动转换为WrappedString实例。

因此,运算符有三种可能的应用程序+应该返回一个实例,示例底部的WrappedString调用说明了这一点。println()

import scala.language.implicitConversions

object test extends App {
  case class WrappedString(value: String) {
    override def toString = s"[$value]"
    def +(right: WrappedString) = WrappedString(value + right.value)
  }

  object WrappedString {
    implicit def fromString(value: String) = WrappedString(value)
  }

  implicit class StringExtensions(value: String) {
    // Isn't actually used in the code below.
    def +(right: WrappedString) = WrappedString(value) + right
  }

  println(WrappedString("a") + WrappedString("b")) // [ab]
  println(WrappedString("a") + "b") // [ab]

  // Would like this to print `[ab]`
  println("a" + WrappedString("b")) // a[b]
}

出于某种原因,第三个示例打印a[b]. 在与字符串连接以产生最终结果之前,该WrappedString实例被转换为 a 。String"a"

如何更改WrappedString和/或隐含的声明,以便在第三个示例中,在应用运算符之前将其String转换为 a ?WrappedString+

[1]:在我正在处理的项目中,包装后的字符串以ANSI SGR 转义码的形式携带格式信息。

4

2 回答 2

1

编译器永远不会选择隐式+方法而不是显式+方法,这是String类所拥有的,所以"a" + WrappedString("b")总是会变成"a".+(WrappedString("b").toString).

要强制转换,您可以选择一个不同的方法名称,一个String没有的方法名称,以及一个隐式类,这意味着它不能是一个case类。这样你就不需要implicitConversions导入,这是不鼓励的。

implicit class WrappedString(val value: String) {
  override def toString = s"[$value]"
  def +#(right: WrappedString) = WrappedString(value + right.value)
}

WrappedString("a") +# WrappedString("b") // [ab]
WrappedString("a") +# "b" // [ab]
"a" +# WrappedString("b") // [ab]
"a" +# "b" // also [ab]

如果您不使用标准库中已经存在的类名,这也可能会有所帮助。

于 2018-07-20T15:35:56.177 回答
0

我想知道当您手动将所有值包装在WrappedString自己中时,您真正想要隐式转换的位置。看来您需要类似右关联运算符之类的东西,Scala 支持:在函数名称的末尾使用。

例如:

case class WrappedString(value: String) {
    override def toString = s"[$value]"
    def +(right: WrappedString) = WrappedString(value + right.value)
    def +:(right: WrappedString) = right + WrappedString(value)
}

println("a" +: WrappedString("b")) // [ab]

除此之外,您可以通过指定以下类型来强制转换:

println(("a": WrappedString) +: WrappedString("b")) // [ab]

或者可能只是将其移至单独的功能。很高兴得到纠正,但是编译器怎么会知道你的意图是什么,因为它String已经有了一个有效的+函数,并且探索所有可能的转换不会很有效。

于 2018-07-20T15:35:45.533 回答