scala - Scala中的右关联方法有什么用?

标签 scala operators operator-precedence

我刚刚开始玩Scala,我刚刚学习了如何使方法成为右关联的(与命令式面向对象语言中常见的更传统的左关联性相反)。

最初,当我在Scala中看到示例代码cons一个列表时,我注意到每个示例始终在右侧都有该List:

println(1 :: List(2, 3, 4))
newList = 42 :: originalList

但是,即使一遍又一遍地看到它,我也没有三思而后行,因为(当时)我不知道::List的一种方法。我只是假定它是一个运算符(再次,就Java中的运算符而言),并且关联性并不重要。 List始终出现在示例代码的右侧这一事实似乎是偶然的(我认为这可能只是“首选样式”)。

现在我知道了:它必须以这种方式编写,因为::是右关联的。

我的问题是,能够定义右关联方法有什么意义?

是纯粹出于美学原因,还是在某些情况下右联想会比左联想有某种好处?

从我(新手)的 Angular 来看,我真的不明白
1 :: myList

有什么比
myList :: 1

但这显然是一个微不足道的例子,我怀疑这是一个公平的比较。

最佳答案

简短的答案是,通过使程序员类型与程序实际行为保持一致,右联想可以提高可读性。
因此,如果您键入“1 :: 2 :: 3”,则会返回一个List(1、2、3),而不是以完全不同的顺序返回一个List。
那是因为'1 :: 2 :: 3 :: Nil'实际上是

List[Int].3.prepend(2).prepend(1)

scala> 1 :: 2 :: 3:: Nil
res0: List[Int] = List(1, 2, 3)

两者都是:
  • 更具可读性
  • 更有效(对于prepend为O(1),对于假设的append方法为O(n))


    (提醒,摘自Programming in Scala书)
    如果将一种方法用在运算符表示法中,例如a * b,则该方法在左侧操作数上调用,就像a.*(b)一样—除非方法名以冒号结尾。
    如果方法名称以冒号结尾,则会在右侧的操作数上调用该方法。
    因此,在1 :: twoThree中,对::调用twoThree方法,传入1,如下所示:twoThree.::(1)

    对于列表,它起到附加操作的作用(列表似乎附加在“1”之后,形成“1 2 3”,实际上是在列表前面的1)。
    类列表没有提供真正的追加操作,因为追加到列表所需的时间随列表的大小线性增长,而加上::则需要固定的时间myList :: 1会尝试将myList的全部内容添加到'1'之前,这比将1添加到myList之前要长(如在1 :: myList中)

    注意:无论运算符具有何种关联性,其操作数均为
    总是从左到右评估。
    因此,如果b是一个表达式,而不仅仅是对不可变值的简单引用,则::: b更精确地视为以下块:
    { val x = a; b.:::(x) }
    

    在此块中,a仍在b之前进行评估,然后评估结果
    作为操作数传递给b的:::方法。

    why make the distinction between left-associative and right-associative methods at all?



    在实际将操作应用于右表达式时,这样可以保持通常的左关联操作('1 :: myList')的外观,因为;
  • 效率更高。
  • ,但以相反的关联顺序(“1 :: myList”与“myList.prepend(1)”对比)更具可读性

    据您所知,“句法糖”据我所知。
    注意,例如对于foldLeft,它们可能具有gone a little to far(与'/:'右关联运算符等效)

    要包括您的一些评论,请稍作改写:

    如果您考虑左关联的“附加”功能,则应编写“oneTwo append 3 append 4 append 5”。
    但是,如果将3、4和5附加到oneTwo(您将以其编写的方式假定),则它将为O(N)。
    与“::”相同,如果用于“追加”。但事实并非如此。它实际上是为“前置”

    这意味着“a :: b :: Nil”适用于“List[].b.prepend(a)

    如果'::'在前面,但仍保持左联想,则结果列表的顺序将错误。
    您可能希望它返回List(1、2、3、4、5),但最终会返回List(5、4、3、1、2),这对于程序员而言可能是意外的。
    这是因为,您要做的是按照左关联顺序进行的:
    (1,2).prepend(3).prepend(4).prepend(5) : (5,4,3,1,2)
    

    因此,右关联性使代码与返回值的实际顺序匹配。

  • 关于scala - Scala中的右关联方法有什么用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1162924/

    相关文章:

    Prolog 运算符优先级和规则匹配

    scala - 如何将此 "Wed, 10 Jun 2020 10:16:24 GMT"转换为此 "2020-05-10T12:30:45"datetimestr 格式

    lua - Lua中~=运算符是什么意思?

    scala - scala 对推断类型的 "acceptable complexity"有什么限制?

    c - 用于分组的圆括号是否被视为运算符?

    arrays - Python '==' 运算符给出了错误的结果

    c++ - 一元否定运算符会出现在函数调用之前吗?

    c++ - 当#defines 使用其他#defines 时,顺序重要吗?

    scala - 应该避免 x._1,x._2... 语法吗?

    java - 如何在 Scala 中匿名实现 Java 接口(interface)?