String 重写字符串等于
我正在写一个DSL,我最终希望能够拥有自己的字符串类型,在这里我可以做类似的事情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
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中提供的方式相比)。