String 重写字符串等于

String 重写字符串等于,string,scala,dsl,String,Scala,Dsl,我正在写一个DSL,我最终希望能够拥有自己的字符串类型,在这里我可以做类似的事情 var s:BString = "123" if ("123" == s) ... 而且 var d:Double = s + 5.0 我基本上使用了5.0+s的隐式转换 通过重写我的'BString'类中的equals方法,我还有==以一种方式工作,其中第一个参数(左侧)是一个BString 问题在于如何重写Java字符串equals。我看了String.equals()源代码,equals方法采用了一个Ja

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

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

var d:Double = s + 5.0
我基本上使用了5.0+s的隐式转换

通过重写我的'BString'类中的equals方法,我还有==以一种方式工作,其中第一个参数(左侧)是一个BString

问题在于如何重写Java字符串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
  }

}

虽然我不喜欢实现诸如将字符串添加到double(反之亦然)之类的语言行为,但您可以这样做:

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
的定义,使其模式与其参数的运行时类型匹配,并且我还通过编写
(“1.1”:BString)
向打字机提示“1.1”实际上是一个
BString


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

String
是JDK中的最后一个类,原因很多-如果允许您修改其
equals
方法,基本上可能会破坏JVM的整个安全模型!(有关详细原因,请参阅。)

因此,您在DSL中所能做的最好的事情就是引入一个未为
String
定义的新操作符,例如
===
,并确保您有一个
String
BString
的隐式转换:

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

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

你也可以考虑制作你的<代码> BStudio类最终。编写一个正确的

equals
方法在面对继承时可能很困难或不可能-考虑一下您在尝试比较
字符串
对象
时已经看到的不对称性,查找和应用隐式转换的过程是由写入类型检查的表达式失败驱动的,因为调用的方法不存在于应用它的静态已知表达式类型中。由于字符串有一个合适的
equals
,隐式转换永远不能用您自己的转换来代替它。谢谢@Randall,这是我得出的结论。谢谢大家的回答。结论是Java字符串是最终的,除了定义另一个将通过隐式转换调用的方法外,字符串相等没有其他解决方法。谢谢@fotNelton。我只实现了一个现有的DSL,因此添加:BString提示将是一件棘手的事情。向int等添加字符串是一种代码味道,你是对的,但这正是我试图模仿的。是的,必须手动添加
:BString
,这确实令人沮丧。正如在另一个答案中所建议的,而且在我看来,解决这个问题没有简单的方法,因为如果你写
“1.1”==y
,编译器怎么知道你想要
等于
方法,因为你显然在
字符串上调用它。我能想到的另一件事是像
.b
这样的后缀操作符,它将常规
字符串
s转换为
BString
s(与
RegEx
s在Scala中提供的方式相比)。