为什么API会返回'void'?

JBR*_*son 23 c# c++ api

在编写API或可重用对象时,是否存在任何技术原因导致返回'void'的所有方法调用不应仅返回'this'(*在C++中为此)?

例如,使用字符串类,我们可以做这样的事情:

string input= ...;
string.Join(input.TrimStart().TrimEnd().Split("|"), "-");
Run Code Online (Sandbox Code Playgroud)

但我们不能这样做:

string.Join(input.TrimStart().TrimEnd().Split("|").Reverse(), "-");
Run Code Online (Sandbox Code Playgroud)

..beause Array.Reverse()返回void.

还有许多其他示例,其中API具有许多返回void的操作,因此代码最终看起来像:

api.Method1();
api.Method2();
api.Method3();
Run Code Online (Sandbox Code Playgroud)

..但完全有可能写:

api.Method1().Method2().Method3()
Run Code Online (Sandbox Code Playgroud)

..如果API设计师允许这样做.

遵循这条路线有技术原因吗?或者它只是一种风格的东西,表示可变性/新对象?

(x-ref 关于返回虚空的文体问题)


结语

我已经接受了Luvieere的答案,因为我认为这最能代表意图/设计,但似乎有一些流行的API示例与此有所不同:

在C++中cout << setprecision(..) << number << setwidth(..) << othernumber;似乎改变了cout对象,以便修改插入的下一个数据.

在.NET中,Stack.Pop()并且Queue.Dequeue()都返回一个项目,但改变集合了.

向ChrisW和其他人道歉,详细了解实际的性能成本.

luv*_*ere 26

返回void状态的方法更清楚,它们有副作用.返回修改结果的那些应该没有副作用,包括修改原始输入.使方法返回void意味着它更改其输入或API的其他内部状态.

  • @JBRWilkinson在VDM中给出的堆栈的语义定义描述了以下操作:init: - > Stack; push:N x Stack - > Stack; 顶部:堆栈 - >(NU ERROR); remove:Stack - > Stack; isempty:Stack - > Boolean否则删除AND返回的东西.这告诉我,最初的意图是明确区分引起副作用的呼叫和纯粹的呼叫.因此,Pop()方法是一种语法上的便利,而不是一种正式的实践. (2认同)

Mar*_*off 19

如果你Reverse()返回了a string,那么对于API的用户来说,它是否返回一个新的字符串或同一个字符串就不会显而易见.

string my_string = "hello";
string your_string = my_string.reverse(); // is my_string reversed or not?
Run Code Online (Sandbox Code Playgroud)

这就是为什么,例如,在Python中,list.sort()返回None; 它区分了就地排序sorted(my_list).


Chr*_*isW 5

遵循这条路线有技术原因吗?

C++设计指南之一是"不要为不使用的功能付费"; this对于许多人(我,对于一个人)不倾向于使用的功能,返回会有一些(轻微的)性能损失.

  • JBRWilkinson无论this指针在哪里,它应该是调用进程返回调用进程时的this指针.实际上,使用MSVC,`this`指针位于`ecx`寄存器中,并且返回代码位于`eax`寄存器中:因此性能损失将是/的结尾处的额外`mov ecx,eax`指令.每个被调用的子程序. (3认同)
  • @JBRWilkinson额外的操作码可以在不使用时进行优化,只有当被调用的例程知道它被调用的位置时,即当它被内联时(但内联一切都会有自己的性能问题). (3认同)

Han*_*Gay 5

许多其他人提到的技术原理(void强调该函数具有副作用的事实)被称为Command-Query Separation

虽然这个原则有利有弊,例如(主观上)更清晰的意图与更简洁的 API,但最重要的部分是保持一致