使 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]

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

...
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 是什么(当时)的情况下,我只是因为 UFCS 很有意义,尤其是在与多重分发结合使用时,才将 UFCS 支持添加到 NGS 中。很高兴听到 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

嘿 Ilya,很高兴看到您也喜欢 UFCS 的想法。对我来说感觉很自然。

回复 作者 Ilya Sher (未验证)

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/ 可以让您无需安装即可试用。

您是对的!我没有想到。我将在我的下一篇文章中包含它。

回复 作者 Piotrek (未验证)

您是对的!我没有想到。我将在我的下一篇文章中包含它。

回复 作者 Piotrek (未验证)

正如您提到的,它是语法糖。提高代码可读性 - 使其更接近真实英语。那么为什么不
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 相比,语法非常赏心悦目 :)

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

回复 作者 Steeve

知识共享许可协议本作品根据知识共享署名-相同方式共享 4.0 国际许可协议获得许可。
© . All rights reserved.