我希望通过重载列表运算符和Scala
在Nil
中实现builder pattern。但显然它没有用。
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 )
}
为什么以及如何成功?
答案 0 :(得分:2)
正如您在Scala spec
中找到的那样操作员的关联性由操作员的最后一个字符决定。以冒号':'结尾的运算符是右关联的。所有其他运算符都是左关联的。
稍后:
如果连续的中缀操作
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)
这样做是因为::
是传统上在函数式编程中用于构建不可变List
的运算符,这正是那里所需的语义。因此,如果您真的想使用::
,您应该制作如下代码:
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
然后
println(SomeBuilder :: "aaa" :: "bbb" :: Nil)
会奏效。但请注意这是多么可怜的低效率:有效地将每个字符串旋转两次。您必须执行此操作,因为::
是右关联的,并且没有有效的perpend
方法。
总结您可以使这种语法有效,但使用::
这是一个非常糟糕的主意。如果你几乎使用其他任何东西,你会更好。
Sidenote#1 :使用Nil
也是一个相当糟糕的主意,因为它会与scala.collection.immutable.Nil
发生冲突(即空List
1}})。
Sidenote#2 :虽然现代JVM实施可以优化synchronized
,但在很多情况下,您最好使用java.lang.StringBuilder
代替java.lang.StringBuffer
在这种非多线程环境中
使用++
所以主要问题是使用::
。如果您使用其他运算符,例如++
,它应该可以找到。
如果是这样的语法
println(new SomeBuilder ++ "aaa1" ++ "bbb2" build)
或
println((new SomeBuilder ++ "aaa1" ++ "bbb2").build)
对你没用,你可以使用这样的代码:
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
}
如果您出于某种原因喜欢更接近您的示例的内容,例如
println(new SomeBuilder ++ "aaa1" ++ "bbb2" ++ BuildString)
您可以使用以下代码:
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