覆盖String等于

时间:2014-01-21 17:46:38

标签: string scala dsl

我正在写一个DSL,我最终希望能够拥有自己的字符串类型,我可以在这里做一些事情,比如

var s:BString = "123"
if ("123" == s) ...

以及

var d:Double = s + 5.0

我基本上使用隐式转换以及5.0 + s

我也有= =通过覆盖我的'BString'类中的equals方法来工作,其中第一个参数(左侧)是一个BString。

问题是以某种方式覆盖Java String equals。我看了一下String.equals()源代码,而equals方法接受了一个Java对象,我似乎无法使用隐式转换。然后equals方法将对象转换为字符串,所以我认为除非我有(final)String的子类我是SOL。

还有其他方法吗?想法?

class BString(val string: String) {
    override def toString() = string
    def toDouble:Double = string.toDouble
    def +(bs:BString) = string.toDouble + bs.toDouble
    def +(d:Double) = string.toDouble + d
    override def equals(x$1:Any):Boolean = string == x$1.toString
} 

object Test {

  implicit def string2BString(x:String)  = new BString(x)
  implicit def double2BString(x:Double)  = new BString(x.toString)
  implicit def bString2Object(x:BString) = { // never being reached
    println("OO");
    x.asInstanceOf[Object]
  } 

  def main(args: Array[String]) {

    var y:BString = "1.1"
    println(y + 1.1)        //2.2
    println(1.2 + y)        //2.3
    println("1.1" == y)     // false :-(
    println("1.1" equals y) // false :-(
    println("1.1" equals bString2Object(y)) // also false
    println(y == "1.1")     // true
  }

}

2 个答案:

答案 0 :(得分:0)

尽管我不喜欢实现语言行为,比如在双打中添加字符串(反之亦然),这就是你可以做的:

import scala.language.implicitConversions

class BString(val string: String) {
  def toDouble: Double = string.toDouble
  def +(bs: BString): Double = string.toDouble + bs.toDouble
  def +(d: Double): Double = string.toDouble + d
  override def equals(other: Any) = other match {
    case bs: BString => string == bs.string
    case os: String  => string == os
    case _           => false
  }
}

object BString {
  implicit def string2BString(x: String) = new BString(x)
  implicit def double2BString(d: Double) = new BString(d.toString)
}

object Test extends App {
  val y: BString = "1.1"
  println(y + 1.1)                   // 2.2
  println(1.2 + y)                   // 2.3
  println(("1.1": BString) == y)     // true
  println(("1.1": BString) equals y) // true
  println(y == "1.1")                // true
}

正如你所看到的,我已经改变了equals的定义,使得它在其参数的运行时类型上匹配模式,并且我还给了typer一个暗示“1.1”真的写BString撰写("1.1": BString)

编辑:另请注意,您实际上不需要def +(d: Double)方法。

答案 1 :(得分:0)

String是JDK中的最后一个类,原因很多 - 如果你被允许使用它的equals方法,你基本上可以破坏JVM的整个安全模型! (有关详细原因,请参阅this question。)

既然如此,你能在DSL上做的最好的就是引入一个未定义String的新运算符,例如===,并确保你有隐式转换可用于StringBString

class BString(val string: String) {
  def ===(other: BString) = TODO
}

object BString {
  implicit def string2BString(x: String) = new BString(x)
}

你也可以考虑让你的BString课程最终成绩。面对继承,编写正确的equals方法可能很困难或不可能 - 考虑一下您在尝试比较StringObject时已经目睹的不对称性,并查看{{ 3}}彻底解决问题。