测试Open Live Writer
近10年D语言在社区驱动下得到巨大发展,语言核心去芜存菁,广泛吸收;标准库不断扩充;语法越来越“对人类友好”;betterC和importC使得D语言与C语言越来越成为一家人,为底层开发在做坚实的奠基;以vibe-d和hunt frame work为首的众多跨平台网络库,使得开发web框架和应用几乎与控制台和桌面程序一样的容易、简
UFCS,Uniform Function Call Syntax.统一函数调用语法,或者,我按自己的理解,称为函数一致性调用语法,使得语言更贴近人类表达习惯,同时使得函数链调用变得非常可行,并且简单、简便。
对于一个模块级(module)自由函数,如果满足以下两个条件,即可像一个对象的成员方法一样去调用:
- 这个对象没有(或不能有)一个这样的成员方法;
- 这个自由函数的第一个参数与该类型匹配(该类,super类,可安全地类型转换成为该类型等)
到此,这个对象可以是任何类型,都可有如调用自己的成员方法一样去调用这个自由成员。
听起来还是有些别扭,看示例会更容易明白究竟是怎么一回事:
1 /+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 这个小程序演示D语言UFCS,函数一致性调用语法。 3 一般地,如果有一个模块级自由函数void print(string msg), 4 我们理所当然地这样去调用: 5 print("早上好!"); 6 7 当以下两件条件满足时: 8 1.string类型没有print()这样一个方法; 9 2.自由函数的参数类型为string,正好是string类型 10 11 string.print() 即可通过编译器允许,即与 12 print("早上好”); 13 一样。 14 事实上由于UFCS这个特性,编译器首先查看string类型有没有 15 print()这个方法,如果有,就调用;如果没有,则在模块级 16 查看有没有print(stirng)这样一个自由函数,如果有,就调 17 用它。 18 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++/ 19 20 module ufcstest; 21 import std.stdio; 22 23 void print(string msg) 24 { 25 writeln(msg); 26 } 27 28 void main() 29 { 30 "Hello UFCS".print(); 31 "早上好".print; 32 33 readln; 34 }
既然UFCS可以这样玩,那试试语言标准库标准输出函数writeln:
1 module ufcstest; 2 import std.stdio; 3 4 /* 5 void print(string msg) 6 { 7 writeln(msg); 8 } 9 */ 10 void main() 11 { 12 writeln("标准库writeln标准调用方法:"); 13 writeln("晚上好"); 14 writeln("我爱世界杯"); 15 16 writeln("=============================="); 17 writeln("UFCS调用:"); 18 19 "晚上好".writeln(); 20 "我爱世界杯".writeln; 21 22 readln; 23 }
下面示例一个非常简单的函数链调用:
1 module ufcstest; 2 import std.stdio; 3 4 /* 5 void print(string msg) 6 { 7 writeln("标准库writeln标准调用方法:"); 8 writeln("晚上好"); 9 writeln("我爱世界杯"); 10 11 writeln("=============================="); 12 writeln("UFCS调用:"); 13 14 "晚上好".writeln(); 15 "我爱世界杯".writeln; 16 } 17 */ 18 19 double add(double a,double b) 20 { 21 return a+b ; 22 } 23 24 void main() 25 { 26 writeln("比起嵌套调用:writeln(add(10,20));"); 27 writeln("add(10,20).writeln更符合连贯性思维。"); 28 add(10,20).writeln; 29 30 readln; 31 }
可以初步稍稍想象一下,类成员函数有一些是返回类对象本身,再结合自由函数的UFCS,加之标准库,泛型,mixin等语言核心特性在一起,这个组合将是非常强大的。
最后我们借用网上的一段代码来结束这趟Open Live Writer之旅。对一个数组内元素进行加减乘除的操作然后打印到控制台,还是借用标准输出泛型自由函数writeln(T...)(T args)第一个参数可以是任何类型的这个特性,对数组操作进行链式函数调用。
1 module chaincall; 2 3 import std.stdio; 4 5 //数组slice每个元素被除以divisor后,返回整个数组 6 int[] divide(int[] slice,int divisor) 7 { 8 int[] result; 9 result.reserve(slice.length); 10 11 foreach(value;slice) 12 { 13 result~=value/divisor; 14 } 15 return result; 16 17 } 18 19 //数组slice每个元素被乘以multiplier后,返回整个数组 20 int[] multiple(int[] slice,int multiplier) 21 { 22 int[] result; 23 result.reserve(slice.length); 24 25 foreach(value;slice) 26 { 27 result~=value*multiplier; 28 } 29 return result; 30 } 31 32 //去除掉数组里的偶数元素,返回结果数组 33 int[] evens(int[] slice) 34 { 35 int[] result; 36 result.reserve(slice.length); 37 38 foreach(value;slice) 39 { 40 if(value%2) 41 { 42 result~=value; 43 } 44 } 45 return result; 46 } 47 48 void main() 49 { 50 int[] values=[1,2,3,4,5]; 51 //WYSIWYG所见即所得字符串表达方式: 52 string prompt=" 53 对数组values进行以下操作: 54 第一步:对各个元素乘以10; 55 第二步:对各个元素除以3; 56 第三步:返回只有奇数值的数组; 57 第四步:打印结果数组(只有奇数值) 58 59 一般强类型编译型语言基本都是这样调用的: 60 61 "; 62 prompt.writeln; 63 writeln("writeln(evens(divide(multiple(10),3)));\n结果是:"); 64 writeln(evens(divide(multiple(values,10),3))); 65 writeln("这个调用顺序显然不符合上面所列,即非原本所思"); 66 67 writeln("且看D语言UFCS调用语法,其顺序和人想的一样:"); 68 writeln("writeln(values.multiple(10).divide(3).evens());\n"); 69 70 writeln("或者干脆:\nvalues.multiple(10).divide(3).evens.writeln;\n结果是:\n"); 71 values.multiple(10).divide(3).evens.writeln; 72 73 writeln("Done."); 74 readln; 75 }