问题描述
现有的C API如下所示:
There is an existing C API that looks like this:
//data
typedef struct {int properties;} Widget;
//interface
Widget* SetWidth(Widget *const w, int width){
// ...
return w;
}
Widget* SetHeight(Widget *const w, int height){
// ...
return w;
}
Widget* SetTitle(Widget *const w, char* title){
// ...
return w;
}
Widget* SetPosition(Widget *const w, int x, int y){
// ...
return w;
}
第一个参数始终是指向实例的指针,并且转换实例的函数始终将其作为指针返回.
The first parameter is always a pointer to the instance, and the functions that transform the instance always return it as a pointer.
我认为这样做是为了支持某种方法链接?
I assume this was done to support some kind of Method Chaining?
当函数作为方法存在于对象范围内时,方法链接在语言中才有意义.给定API处于当前状态,我就这样使用它:
Method Chaining makes sense in languages when the functions exist as methods inside the scope of the object. Given the API in its current state, I'm left using it like this:
int main(void) {
Widget w;
SetPosition(SetTitle(SetHeight(SetWidth(&w,400),600),"title"),0,0);
}
我可以使用C中的任何技术来获得与其他语言相同的流畅性吗?
Are there any techniques I can use in C to get the same fluidity as in other languages?
推荐答案
在C语言中,没有语法技巧可以实现方法链接,这在某些其他语言中也可以使用.在C语言中,您将编写单独的函数调用,将对象指针传递给每个函数:
There is no syntax trick in C to achieve method chaining as may be used in some other languages. In C, you would write separate function calls, passing the object pointer to each function:
Widget *w = getWidget();
widgetSetWidth(w, 640);
widgetSetHeight(w, 480);
widgetSetTitle(w, "Sample widget");
widgetSetPosition(w, 0, 0);
使用C ++和其他OOP语言进行方法调用也可以做到这一点:
The same can be done with method calls in C++ and other OOP languages:
Widget *w = getWidget();
w->SetWidth(640);
w->SetHeight(480);
w->SetTitle("Sample widget");
w->SetPosition(0, 0);
使用上述API,并假设每个方法都返回 this
对象,则方法链接语法如下所示:
With the above APIs, and assuming each method returns the this
object, the method chaining syntax looks like this:
getWidget()->SetWidth(640)->SetHeight(480)->SetTitle("Sample widget")->SetPosition(0, 0);
这是否比单独的语句更具可读性取决于口味和本地编码约定.我个人觉得它很麻烦而且很难阅读.在代码生成方面有一个小的优势:无需为下次调用从局部变量中重新加载对象指针.这种微不足道的优化几乎无法证明链接语法的合理性.
Whether this is more readable than the separate statements is a matter of taste and local coding conventions. I personally find it cumbersome and harder to read. There is a small advantage in terms of code generation: the object pointer does not need to be reloaded from a local variable for the next call. This minuscule optimisation hardly justifies the chaining syntax.
一些程序员尝试通过这种方式使其更美味:
Some programmers try and make it more palatable this way:
getWidget()
-> SetWidth(640)
-> SetHeight(480)
-> SetTitle("Sample widget")
-> SetPosition(0, 0);
同样,关于口味和编码约定...但是C等效项显然显得笨拙:
Again, a matter of taste and coding conventions... But the C equivalent definitely looks awkward:
Widget *w = widgetSetPosition(widgetSetTitle(widgetSetHeight(widgetSetWidth(getWidget(), 640), 480), "Sample widget"), 0, 0);
没有简单的方法可以将此链重组为更具可读性的
And there is no easy way to reorganise this chain into some more readable.
请注意,一些最古老的C库函数也可以链接:
Note that some of the most ancien C library functions can be chained too:
const char *hello = "Hello";
const char *world = "World";
char buf[200];
strcpy(buf, hello);
strcat(buf, " ");
strcat(buf, world);
strcat(buf, "\n");
可以重组为:
strcat(strcat(strcat(strcpy(buf, hello), " "), world), "\n");
但是,这是一种更安全,更可取的方法:
But a safer and much preferred approach is this:
snprintf(buf, sizeof buf, "%s %s\n", hello, world);
有关更多信息,您可能需要阅读以下内容:
For more information, you might want to read this:
还要注意,如果C对象具有用于这些调用的函数指针成员,则可以使用上述所有语法,但是对象指针仍必须作为参数传递.函数指针通常分组为一个结构,指针存储在对象中,该结构类似于C ++虚拟方法的实现,从而使语法稍微重一点:
Note also that if the C object has function pointer members for these calls, all of the above syntaxes could be used, but the object pointer must still be passed as an argument. The function pointers are usually grouped in a structure to which a pointer is stored in the object, mimicking the implementation of C++ virtual methods, making the syntax slightly heavier:
Widget *w = getWidget();
w->m->SetWidth(w, 640);
w->m->SetHeight(w, 480);
w->m->SetTitle(w, "Sample widget");
w->m->SetPosition(w, 0, 0);
也可以束缚这些,但并没有真正的收获.
Chaining these is possible too, but for no real gain.
最后,应该注意,方法链接不允许显式错误传播.在链接很常见的OOP语言中,可以抛出异常来以某种或多或少的可口方式表示错误.在C语言中,处理错误的惯用方式是返回错误状态,这与返回指向对象的指针相冲突.
Finally, it should be noted that method chaining does not allow for explicit error propagation. In OOP languages where chaining is idiomatic, exceptions can be thrown to signal errors in a more or less palatable way. In C the idiomatic way to handle errors is to return an error status, which conflicts with returning a pointer to the object.
因此,除非保证方法成功,否则建议不要使用方法链并执行迭代测试:
As a consequence, unless the methods are guaranteed to succeed, it is advisable to not use method chaining and perform iterative tests instead:
Widget *w = getWidget();
if (SetWidth(w, 640)
|| SetHeight(w, 480)
|| SetTitle(w, "Sample widget")
|| SetPosition(w, 0, 0)) {
/* there was an error, handle it gracefully */
}
这篇关于如何使方法链接在C语言中流利?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!