Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Scala中重载两个冒号运算符?_Scala_List_Operator Overloading_Builder Pattern - Fatal编程技术网

如何在Scala中重载两个冒号运算符?

如何在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

我希望通过重载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.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,我不知道你不清楚什么。您可以重载运算符,但对于任何典型情况,您都不希望重载运算符使用
。游寿