使 D 成为我最喜欢的编程语言的功能

UFCS 使您能够组合可重用代码,这些代码具有自然的流程,而又不牺牲便利性。
80 位读者喜欢这个。
Coding on a computer

早在 2017 年,我就写过关于为什么 D 编程语言是开发的绝佳选择。但是 D 中有一个突出的功能我没有充分展开:通用函数调用语法 (UFCS)。 UFCS 是 D 中的一种语法糖,它允许像其类型的成员函数一样,在类型(字符串、数字、布尔值等)上链接任何常规函数。

如果您尚未安装 D,请安装 D 编译器,以便您可以自己运行本文中的 D 代码

考虑以下示例代码

// file: ufcs_demo.d

module ufcs_demo;

import std.stdio : writeln;

int[] evenNumbers(int[] numbers)
{
    import std.array : array;
    import std.algorithm : filter;

    return numbers.filter!(n => n % 2 == 0).array;
}

void main()
{
    writeln(evenNumbers([1, 2, 3, 4]));
}

使用您最喜欢的 D 编译器编译此代码,以查看这个简单的示例应用程序的作用

$ dmd ufcs_demo.d
$ ./ufcs_demo
[2, 4]

但是,借助作为 D 内置功能的 UFCS,您也可以以自然的方式编写代码

...
writeln([1, 2, 3, 4].evenNumbers());
...

或完全删除现在多余的括号,使其感觉像 evenNumbers 是一个属性

...
writeln([1, 2, 3, 4].evenNumbers); // prints 2, 4
...

所以完整的代码现在变成

// file: ufcs_demo.d

module ufcs_demo;

import std.stdio : writeln;

int[] evenNumbers(int[] numbers)
{
    import std.array : array;
    import std.algorithm : filter;

    return numbers.filter!(n => n % 2 == 0).array;
}

void main()
{
    writeln([1, 2, 3, 4].evenNumbers);
}

使用您最喜欢的 D 编译器编译并试用。正如预期的那样,它产生相同的输出

$ dmd ufcs_demo.d
$ ./ufcs_demo
[2, 4]

在编译期间,编译器自动将数组作为函数的第一个参数放置。这是一个常规模式,使使用 D 成为一种乐趣,因此它非常符合您对代码的自然思考方式。结果是函数式编程风格。

您可能可以猜到这会打印什么

//file: cool.d
import std.stdio : writeln;
import std.uni : asLowerCase, asCapitalized;

void main()
{
    string mySentence = "D IS COOL";
    writeln(mySentence.asLowerCase.asCapitalized);
}

但只是为了确认

$ dmd cool.d
$ ./cool
D is cool

结合其他 D 功能,UFCS 使您能够组合可重用代码,这些代码具有自然的流程,而又不牺牲便利性。

是时候尝试 D 了

正如我之前写过的,D 是一种很棒的开发语言。从 D 下载页面 很容易安装,所以下载编译器,看看示例,亲自体验 D。

接下来阅读什么
标签
User profile image.
Lawrence 是一位自由职业的全栈工程师(React、Node.Js、D)和 100% Linux 用户。他热爱设计和编码。对 SaaS 和现代 Web 充满热情。

29 条评论

甚至在您开始解释 UFCS 之前,您就已经在使用它了。

`numbers.filter!(n => n % 2 == 0).array`

filter 和 array 都接受一个参数

`array(filter!(n => n % 2 == 0)(numbers))`

您说得对,Jesse。我所做的是提及我之前的帖子,其中确实谈到了 filter 函数...它使用了 UFCS 和模板。所以我不必解释 filter!... 模板函数和不同的调用约定。

回复 作者 Jesse (未验证)

我是网络开发人员,我已经接受了网站的条款和条件

如果您对新语言感兴趣,Nim 也有这个功能

很高兴知道。我认为这是每种现代语言都应该考虑的东西。特别是当它可以在编译时解决而没有运行时成本时。D 似乎在某些方面启发了 Nim。

回复 作者 jyapayne (未验证)

您在 Nim 中没有获得很多“D 优势”。它的语法很有吸引力。

回复 作者 aberba

然后呢?这解决了什么新问题?

嗨。我是 Next Generation Shell 的作者。在不知道 D 或 UFCS 是什么的情况下(当时),我只是因为有道理才在 NGS 中添加了对 UFCS 的支持,特别是当与多重分派结合使用时。很高兴听到 UFCS 功能受到赞扬。

只是为了让您对 NGS 有所了解

--- D ---
module ufcs_demo;

import std.stdio : writeln;

int[] evenNumbers(int[] numbers)
{
import std.array : array;
import std.algorithm : filter;

return numbers.filter!(n => n % 2 == 0).array;
}

void main()
{
writeln([1, 2, 3, 4].evenNumbers);
}

--- NGS ---

F even_numbers(numbers:Arr) {
numbers.filter(F(n) n % 2 == 0)
}

F main() {
[1,2,3,4].even_numbers().echo()
}

---

Next Generation Shell 项目位于 https://github.com/ngs-lang/ngs

UFCS 看起来非常类似于 .Net 扩展。它们之间有什么区别?
编译器是否优化 UFCS 指令的输出?

编译器会重写它,就像您通常编写它的方式一样。所以这对开发者来说很方便。

回复 作者 Rubidium37 (未验证)

我不熟悉 .Net 扩展。但是对于 D,编译器会像您正常调用它的方式一样重写它。所以这对程序员来说是一种方便的语法。

所以 1.add(2): 在编译期间被重写为 add(2,2)。

回复 作者 Rubidium37 (未验证)

看起来像 Elixir、Elm、Haskell 等中的管道运算符,或者 Clojure 中的箭头宏。

- 我不明白这比编写方法好在哪里
- 如果您以后需要添加参数会发生什么?
- 将方法伪装成属性使其难以理解调用它们的性能影响(读取属性是空操作,调用函数则不是)
- 向标准类型添加属性和方法充其量是很奇怪的,最坏的情况是非常令人困惑
:/

嘿 Arthur,UFCS 有助于避免编写类似这样的代码:finish(make(bake(1,4)));

在 D 中,您可以将其写成:bake(1,2).make().finish() 或者更符合习惯的写法,1.bake(3).make.finish。因此,它按照您在阅读代码时在脑海中处理的顺序读取。

任何其他额外的参数都像 1.call(2,3,4,5,...) 这样编写。当然,只有在特定上下文中使用 UFCS 才有意义。

UFCS 实际上只是一种语法技巧。它不会带来额外的性能成本。D 编译器在编译期间将其重写为普通样式。但对于程序员来说,UFCS 只是美化了您的代码。因此,与使用类相比,它更轻量级。有时人们编写类来获得类似的感觉,但使用 D UFCS 可以给您带来这种体验。UFCS 没有内置到类型中,它只是一种语法糖。

回复 作者 Arthur W. (未验证)

很棒,伙计们。学习 D 编程非常有趣。我的第一门编程语言是 Pascal,然后是 VBA。我曾经认为 D 很无聊,因为我转向了格式化和脚本语言,例如 Rubby n Rays 和 Python。我现在知道 D 与 Pascal 和 .NET 有一些相似之处。我喜欢这种集成。我可以轻松地使用 VBA API 管道。最终会尝试 D。

偶数函数也可能只是 filter! (...) 的别名。

您甚至不需要下载编译器就可以试用。有一个 https://run.dlang.io/ 可以让您无需安装即可试用。

正如您所说,它是语法糖。提高代码可读性 - 使其更接近真实的英语。所以为什么不
writeln.mySentence.asLowerCase.asCapitalized;

或者更接近
print mySentence asLowerCase asCapitalized

很想看到这样的语言。

或者使其成为单行代码

import std.stdio : writeln;
import std.uni : asLowerCase, asCapitalized;

void main()
{
"D IS COOL"
.asLowerCase
.asCapitalized
.writeln;
}

回复 作者 aberba

我会尝试 UFCS,看起来很酷!??

我非常喜欢 D,以及它从 C/C++ 发展的感觉,很难相信自从发布以来已经 20 年了。这些天它看起来像是 C/C++ 和一点 ruby 的混合体。我希望我能在专业领域中使用它。去年,我不得不清理用 C++ 编写的绝对混乱的代码,这些代码泄漏了 GB/s 的内存(不骗你),这将是一个用 D 重写的绝佳项目。对于像我这样的老 C/C++ 程序员来说,与像时下流行的 Rust 相比,语法非常赏心悦目 :)

嗨,史蒂夫,我经常看到类似的评论。大多数 D 程序员也是/曾经是 C++ 程序员。这也是 D 具有最强大的 C/C++ 代码互操作性的部分原因。

回复 作者 史蒂夫

Creative Commons License本作品根据 Creative Commons Attribution-Share Alike 4.0 International License 许可。
© . All rights reserved.