【问题标题】:Why is there no "compound method call statement", i.e. ".="?为什么没有“复合方法调用语句”,即“.=”?
【发布时间】:2010-09-30 08:47:33
【问题描述】:

许多编程语言已经有复合语句+=-=/= 等。一种相对较新的编程风格是将方法调用“链接”到彼此上,例如在 Linq、JQuery 和 Django 的 ORM 中。

我有时比我想的更频繁地发现需要在 Django 中执行此操作:

# Get all items whose description beginning with A
items = Items.objects.filter(desc__startswith='A')
if something:
    # Filter further to items whose description also ends with Z
    items = items.filter(desc__endswith='Z')

我认为如果有一个复合方法调用语句,例如.=,它可以像这样工作:

items = Items.objects.filter(desc__startswith='A')
if something:
    items .= filter(desc__endswith='Z')
  • 是否有任何编程语言支持此功能或类似功能?
  • 如果答案是否定的,为什么不呢?
  • 这种编程风格真的那么新颖吗?
  • 是否有任何 PEP(Python 增强提案)支持这个想法?

【问题讨论】:

  • 是对我来说还是这听起来像一个社区维基?
  • @Cristian Ciupitu:确实如此,所以我改了。
  • 看到程序员表现得好像打字是他们工作中最重要的部分,所以我总是很惊讶,因此即使节省三个键击也值得添加带有可疑语义的不透明语法。
  • @只是我的正确意见:我不是想保存击键,我只是想问是否存在类似的东西。语法和语义并不比 += 等不透明或可疑。我怀疑 += 的实现是因为程序员想要保存击键...

标签: jquery python linq programming-languages syntax


【解决方案1】:

Perl 6 支持此功能。

【讨论】:

  • 又一个不惹珍珠的理由。我发誓我不会去找他们。他们只是落在我的腿上。
  • @AaronMcSmooth:+1,但拼写为 Perl。
  • 这太尴尬了。其中一个拼写错误,例如当我输入“f”而不是 5 时。只是希望我可以编辑...
【解决方案2】:

我无法回答这些问题,而且我不确定我对此有何看法,因为我以前从未见过它,但它确实有一个有趣的应用:所有就地运算符都已过时。

a = 1
a .= __add__(1)
a .= __mul__(2)

当然,写成a += 1 更清楚,但是如果这种语法在语言设计的早期出现,并且__add__ 方法不那么丑陋(例如,只是add),那么今天的语言可能今天的运营商减少了 11 个

(当然,这还有其他含义——特别是,从__iadd____add__ 的自动回退将丢失。不过,这是一个有趣的概念。)

【讨论】:

  • (这个网站有时很笨。为什么要让我输入验证码?我没有足够的使用网站来证明我是一个真正的用户吗?)跨度>
【解决方案3】:

恕我直言,我不喜欢它。

想象一下,

items .= click(function(){...});

这不再是语法错误,但它没有意义,不是吗?

我可以说它没有意义,因为如果你扩展我的例子,它会是这样的,

items = items.click(function(){...});

items.click(function(){...}); 只会返回对象 items ,您会将其分配给 items

在这个例子中,

items .= filter(desc__endswith='Z');

这是有道理的,但并非对所有对象都适用,也许这就是它没有实现的原因。

至于parent .= children();,后续代码中parent会怎样?

我说的是jQuery方式。

【讨论】:

  • 嗯,对我来说很有意义。也许你可以解释为什么它没有意义?
  • 首先解释一下为什么这句话对你有意义?
  • 它只对返回自己的修改副本的方法有意义。在简单地返回自身的 mutating 方法上使用它没有抓住重点。
  • 鉴于'.'也是小数点,如果允许上述约定,我想知道以下内容会给我们什么:alert(1.===1);​​​ :-)
  • 有点题外话,但这绝不会成为 jQuery 的语法补充,因为 jQuery 不是一种语言,而是 JavaScript 的框架;-) 至于它是否有意义,就我个人而言,我同意 Reigel 关于这个。
【解决方案4】:

Scala 的集合支持就地操作,前提是变量是 var

scala> var L = List("b", "c")
L: List[java.lang.String] = List(b, c)

scala> L ::= "a"

scala> L
res8: List[java.lang.String] = List(a, b, c)

(对于不熟悉Scala的人,::List的一个方法)

这是一种很多人都避免的编程风格,在 Scala 中,您可以通过使用不可变的vals 来避免这种就地突变:

scala> val L = List("b", "c")
L: List[java.lang.String] = List(b, c)

scala> L ::= "a"
<console>:7: error: reassignment to val
       L ::= "a"

【讨论】:

  • 他的问题专门针对就地呼叫操作员。
  • 他问,“有没有任何编程语言支持这个或类似的东西?”。虽然它不是一个运算符(它是编译器的糖)并且它仅适用于不包含字母数字字符的方法,但我想说它足以值得一提。
【解决方案5】:

我在进行 Java 或 C# 编程时经常考虑到这一点,在这些情况下,您会发现自己在分配的两侧不仅重复一个,而且经常重复相同的两个或多个对象引用——例如,您有某个对象的成员那是一个字符串,您想对该字符串调用一些方法并将其分配回成员变量。奇怪的是,它在 Python 中并没有给我带来太多困扰。

您提出的.= 运算符是我在做C# 时想到的一个想法。另一种选择是允许前导点作为被分配对象的简写,如下所示:

foo.bar.str = .lower()  # same as foo.bar.str = foo.bar.str.lower()

Pascal、Modula-2 和 Visual Basic 有一个 with 语句(与 Python 的同名语句不同),如果它存在于 Python 中,您可以编写类似的东西(我在这里称之为“使用”所以它不会被误认为是有效的 Python):

using foo.bar:
    str = str.lower()  # same as foo.bar.str = foo.bar.str.lower()

当您要对单个对象的成员进行大量操作时,这非常方便,因为它允许使用块。但是,这里仍然存在一定程度的冗余,如果您像这样结合最后两个想法,可以消除这种冗余:

using foo.bar:
    str = .lower()

在我看来,这将是一个很好的语法糖,我发现它非常易读,但它似乎在大多数语言设计者的优先级列表中并不高。不过,既然 Python 确实有 Modula-2 的影响,或许它最终会被添加进来并不是不可能的。

【讨论】:

    【解决方案6】:

    Ruby 在某种程度上具有此功能,但实现方式不同。这是通过“破坏性”方法来改变它们被调用的变量。例如,调用 str.split 只返回对象拆分,它不会改变它。但是,如果你调用 str.split!它改变了它。大多数内置数组和字符串方法都有破坏性和非破坏性版本。

    【讨论】:

      猜你喜欢
      • 2011-09-21
      • 2020-04-30
      • 1970-01-01
      • 2019-01-23
      • 1970-01-01
      • 1970-01-01
      • 2015-08-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多