如何在Scala中重载两个冒号运算符?
我希望通过重载list操作符和如何在Scala中重载两个冒号运算符?,scala,list,operator-overloading,builder-pattern,Scala,List,Operator Overloading,Builder Pattern,我希望通过重载list操作符和Nil在Scala中实现。但很明显,它不起作用 class SomeBuilder { val sb : java.lang.StringBuffer = new java.lang.StringBuffer def ::(str : java.lang.String): SomeBuilder = { sb.append(str) this } def Nil(): java.lang.String = { sb.to
Nil
在Scala
中实现。但很明显,它不起作用
class SomeBuilder {
val sb : java.lang.StringBuffer = new java.lang.StringBuffer
def ::(str : java.lang.String): SomeBuilder = {
sb.append(str)
this
}
def Nil(): java.lang.String = {
sb.toString
}
}
object Hello extends App {
println( new SomeBuilder :: "aaa" :: "bbb" :: Nil )
}
为什么以及如何成功?正如您在
操作符的关联性由操作符的最后一个字符决定。以冒号“:”结尾的运算符是右关联的。所有其他操作符都是左关联的
再过一会儿:
如果存在连续的中缀运算e0;op1;e1;op2…opn;en
如果运算符op1,…,opn
具有相同的优先级,则所有这些运算符必须具有相同的关联性。如果所有运算符都是左关联的,则序列将解释为(…(e0;op1;e1);op2;opn
。否则,如果所有运算符都是右关联的,则序列被解释为e0;op1;(e1;op2;(…opn;en)…)
这意味着你的语法
new SomeBuilder :: "aaa" :: "bbb" :: Nil
实际上被解释为
Nil.::("bbb").::("aaa").::(new SomeBuilder)
这样做是因为:
是函数式编程中传统上用来构建不可变的列表的操作符,这正是这里所需要的语义。因此,如果您真的想使用:
,您应该编写如下代码:
object Nil {
class RealBuilder(val sb: java.lang.StringBuilder) {
def ::(str: java.lang.String): RealBuilder = {
sb.append(str.reverse)
this
}
def ::(terminal: SomeBuilder): String = {
sb.reverse.toString
}
override def toString = sb.toString
}
override def toString = sb.toString
}
def ::(str: java.lang.String): RealBuilder = {
new RealBuilder(new java.lang.StringBuilder(str))
}
override def toString = ""
}
sealed trait SomeBuilder
object SomeBuilder extends SomeBuilder
class SomeBuilder {
val sb: StringBuilder = new StringBuilder
def ++(s: String): SomeBuilder = {
sb.append(s)
this
}
def build: String = sb.toString()
override def toString = sb.toString
}
class SomeBuilder {
val sb: StringBuilder = new StringBuilder
def ++(s: String): SomeBuilder = {
sb.append(s)
this
}
def ++(terminator: BuildString): String = sb.toString()
override def toString = sb.toString
}
sealed trait BuildString
object BuildString extends BuildString
然后
println(SomeBuilder :: "aaa" :: "bbb" :: Nil)
会有用的。但请注意,这是多么低效:有效地将每个字符串旋转两次。您必须这样做,因为:
是右关联的,并且没有有效的独立的方法
总结您可以使用这种语法,但使用:
来实现这一点确实是个坏主意。如果你几乎使用任何其他东西,你会变得更好
侧注#1:使用Nil
也是一个相当糟糕的主意,因为它会与scala.collection.immutable.Nil
(即空的列表
)冲突
Sidenote#2:尽管现代JVM实现可以优化同步
,但在许多情况下,您最好使用它,而不是在这种非多线程环境中
使用++
更新相同的内容
所以主要的问题是使用:
。如果您使用其他操作符,如++
,它应该可以找到
如果是这样的话
println(new SomeBuilder ++ "aaa1" ++ "bbb2" build)
或
如果您同意,您可以使用如下代码:
object Nil {
class RealBuilder(val sb: java.lang.StringBuilder) {
def ::(str: java.lang.String): RealBuilder = {
sb.append(str.reverse)
this
}
def ::(terminal: SomeBuilder): String = {
sb.reverse.toString
}
override def toString = sb.toString
}
override def toString = sb.toString
}
def ::(str: java.lang.String): RealBuilder = {
new RealBuilder(new java.lang.StringBuilder(str))
}
override def toString = ""
}
sealed trait SomeBuilder
object SomeBuilder extends SomeBuilder
class SomeBuilder {
val sb: StringBuilder = new StringBuilder
def ++(s: String): SomeBuilder = {
sb.append(s)
this
}
def build: String = sb.toString()
override def toString = sb.toString
}
class SomeBuilder {
val sb: StringBuilder = new StringBuilder
def ++(s: String): SomeBuilder = {
sb.append(s)
this
}
def ++(terminator: BuildString): String = sb.toString()
override def toString = sb.toString
}
sealed trait BuildString
object BuildString extends BuildString
如果出于某种原因,您更喜欢类似于示例的内容,例如
println(new SomeBuilder ++ "aaa1" ++ "bbb2" ++ BuildString)
您可以使用如下代码:
object Nil {
class RealBuilder(val sb: java.lang.StringBuilder) {
def ::(str: java.lang.String): RealBuilder = {
sb.append(str.reverse)
this
}
def ::(terminal: SomeBuilder): String = {
sb.reverse.toString
}
override def toString = sb.toString
}
override def toString = sb.toString
}
def ::(str: java.lang.String): RealBuilder = {
new RealBuilder(new java.lang.StringBuilder(str))
}
override def toString = ""
}
sealed trait SomeBuilder
object SomeBuilder extends SomeBuilder
class SomeBuilder {
val sb: StringBuilder = new StringBuilder
def ++(s: String): SomeBuilder = {
sb.append(s)
this
}
def build: String = sb.toString()
override def toString = sb.toString
}
class SomeBuilder {
val sb: StringBuilder = new StringBuilder
def ++(s: String): SomeBuilder = {
sb.append(s)
this
}
def ++(terminator: BuildString): String = sb.toString()
override def toString = sb.toString
}
sealed trait BuildString
object BuildString extends BuildString
正如你在
操作符的关联性由操作符的最后一个字符决定。以冒号“:”结尾的运算符是右关联的。所有其他操作符都是左关联的
再过一会儿:
如果存在连续的中缀运算e0;op1;e1;op2…opn;en
如果运算符op1,…,opn
具有相同的优先级,则所有这些运算符必须具有相同的关联性。如果所有运算符都是左关联的,则序列将解释为(…(e0;op1;e1);op2;opn
。否则,如果所有运算符都是右关联的,则序列被解释为e0;op1;(e1;op2;(…opn;en)…)
这意味着你的语法
new SomeBuilder :: "aaa" :: "bbb" :: Nil
实际上被解释为
Nil.::("bbb").::("aaa").::(new SomeBuilder)
这样做是因为:
是函数式编程中传统上用来构建不可变的列表的操作符,这正是这里所需要的语义。因此,如果您真的想使用:
,您应该编写如下代码:
object Nil {
class RealBuilder(val sb: java.lang.StringBuilder) {
def ::(str: java.lang.String): RealBuilder = {
sb.append(str.reverse)
this
}
def ::(terminal: SomeBuilder): String = {
sb.reverse.toString
}
override def toString = sb.toString
}
override def toString = sb.toString
}
def ::(str: java.lang.String): RealBuilder = {
new RealBuilder(new java.lang.StringBuilder(str))
}
override def toString = ""
}
sealed trait SomeBuilder
object SomeBuilder extends SomeBuilder
class SomeBuilder {
val sb: StringBuilder = new StringBuilder
def ++(s: String): SomeBuilder = {
sb.append(s)
this
}
def build: String = sb.toString()
override def toString = sb.toString
}
class SomeBuilder {
val sb: StringBuilder = new StringBuilder
def ++(s: String): SomeBuilder = {
sb.append(s)
this
}
def ++(terminator: BuildString): String = sb.toString()
override def toString = sb.toString
}
sealed trait BuildString
object BuildString extends BuildString
然后
println(SomeBuilder :: "aaa" :: "bbb" :: Nil)
会有用的。但请注意,这是多么低效:有效地将每个字符串旋转两次。您必须这样做,因为:
是右关联的,并且没有有效的独立的方法
总结您可以使用这种语法,但使用:
来实现这一点确实是个坏主意。如果你几乎使用任何其他东西,你会变得更好
侧注#1:使用Nil
也是一个相当糟糕的主意,因为它会与scala.collection.immutable.Nil
(即空的列表
)冲突
Sidenote#2:尽管现代JVM实现可以优化同步
,但在许多情况下,您最好使用它,而不是在这种非多线程环境中
使用++
更新相同的内容
所以主要的问题是使用:
。如果您使用其他操作符,如++
,它应该可以找到
如果是这样的话
println(new SomeBuilder ++ "aaa1" ++ "bbb2" build)
或
如果您同意,您可以使用如下代码:
object Nil {
class RealBuilder(val sb: java.lang.StringBuilder) {
def ::(str: java.lang.String): RealBuilder = {
sb.append(str.reverse)
this
}
def ::(terminal: SomeBuilder): String = {
sb.reverse.toString
}
override def toString = sb.toString
}
override def toString = sb.toString
}
def ::(str: java.lang.String): RealBuilder = {
new RealBuilder(new java.lang.StringBuilder(str))
}
override def toString = ""
}
sealed trait SomeBuilder
object SomeBuilder extends SomeBuilder
class SomeBuilder {
val sb: StringBuilder = new StringBuilder
def ++(s: String): SomeBuilder = {
sb.append(s)
this
}
def build: String = sb.toString()
override def toString = sb.toString
}
class SomeBuilder {
val sb: StringBuilder = new StringBuilder
def ++(s: String): SomeBuilder = {
sb.append(s)
this
}
def ++(terminator: BuildString): String = sb.toString()
override def toString = sb.toString
}
sealed trait BuildString
object BuildString extends BuildString
如果出于某种原因,您更喜欢类似于示例的内容,例如
println(new SomeBuilder ++ "aaa1" ++ "bbb2" ++ BuildString)
您可以使用如下代码:
object Nil {
class RealBuilder(val sb: java.lang.StringBuilder) {
def ::(str: java.lang.String): RealBuilder = {
sb.append(str.reverse)
this
}
def ::(terminal: SomeBuilder): String = {
sb.reverse.toString
}
override def toString = sb.toString
}
override def toString = sb.toString
}
def ::(str: java.lang.String): RealBuilder = {
new RealBuilder(new java.lang.StringBuilder(str))
}
override def toString = ""
}
sealed trait SomeBuilder
object SomeBuilder extends SomeBuilder
class SomeBuilder {
val sb: StringBuilder = new StringBuilder
def ++(s: String): SomeBuilder = {
sb.append(s)
this
}
def build: String = sb.toString()
override def toString = sb.toString
}
class SomeBuilder {
val sb: StringBuilder = new StringBuilder
def ++(s: String): SomeBuilder = {
sb.append(s)
this
}
def ++(terminator: BuildString): String = sb.toString()
override def toString = sb.toString
}
sealed trait BuildString
object BuildString extends BuildString
为什么您希望它完全是:
?Scala中以:
结尾的运算符有一种特殊的语义,它似乎与您的示例不匹配。另外,您的Nil
也不会以这种方式工作。为什么您希望它完全是:
?Scala中以:
结尾的运算符有一种特殊的语义,它似乎与您的示例不匹配。另外,你的Nil
也不会那样工作。好吧,如何重载运算符/函数,以获得良好的生成器语法?换句话说:是否可以重载列表创建语法,从而创建我的类,而不是列表?Dima,我不确定你不清楚什么。您可以重载运算符,但对于任何典型情况,您都不希望重载运算符使用:
。你应该使用以:
结尾的运算符,只有当它像对不可变的列表那样“向后”构建目标对象是有意义的时候。那么,如何重载运算符/函数,以获得良好的生成器语法呢?换句话说,是否有可能重载列表创建语法,从而创建我的类,而不是列表?Dima,我不知道你不清楚什么。您可以重载运算符,但对于任何典型情况,您都不希望重载运算符使用:
。游寿