瘦身前后——兼谈C 语言进化[2]

2008-02-23 05:41:04来源:互联网 阅读 ()

新老客户大回馈,云服务器低至5折

进化——两个例子

  先举一个平易近人的例子(Walter Bright——D语言发明者——曾在他的一个presentation中使用这个例子),假如我们想要遍历一个数组,在C里面我们是这么做(或用指针,但是指针有指针自己的问题):

int arr[10];

… // initialize arr

for(int i = 0; i < 10; i)

{

int value = arr[i];



printf

}

  这个貌似简单的循环其实有几个主要的问题:

  1. 下标索引不应该是int,而应该是size_t,int未必能足够存放一个数组的下标。

  2. value的类型依赖于arr内元素的类型,违反DRY,假如arr的类型改变为long或unsigned,就可能发生截断。

  3. 这种for只能对数组工作,假如是另一个自定义容器就不行了。

  在现代C 里面,则是这么做:

for(std::vector<int>::iterator

iter = v.begin();

iter != v.end();

iter) {



}

  其实最大的问题就是一天三遍的写,麻烦。for循环的这个问题上篇讲auto的时候也提到。

  Walter Bright然后就把D里面支持的foreach拿出来对比(当然,支持foreach的语言太多了,这也说明了这个结构的高效性)。

foreach(i; v) {



}

  不多不少,刚好表达了意思:对v中的每个元素i做某某事情。

  这个例子有人说太Na?ve了,其实我也赞成,的确,每天不知道有多少程式员写下一个个的循环结构,究竟有多少出了上面提到的三个问题呢?最大的问题恐怕还是数组越界。此外大家也都亲身体验过违反DRY原则的后果:改了一处地方的类型,编译,发现到处都是类型错误,结果一通“查找——替换”是免不了的了,谁说程式员的时间是宝贵的来着?

  既然这个例子太Nave,那就说一个不那么Nave的。Java为什么要加入closure?以C STL为例,假如我们要:

transform(v1.begin(), v1.end(), v2.begin(), v3.begin(), _1 _2);

  也就是说将v1和v2里面的元素对应相加然后放到v3当中去。这里用了boost.lambda,但大家都知道boost.lambda又是个经典的鸡肋。_1 _2还算凑活,一旦表达式复杂了,或其中牵涉到对其他函数的调用了,简直就是一场噩梦,比如说我们想把v1和v2中相应元素这样相加:f(_1) f(_2),其中f是个函数或仿函数,能够做加权或其他处理,那么我们能够像下面这样写吗:

  transform(…, f(_1) f(_2));

  答案是不行,您得这样写:

transform(…,

boost::bind(std::plus<int>(), boost::bind(f, _1), boost::bind(f, _1))

);

  Lisper们笑了,Haskeller们笑了,就连Javaer们都笑了。It’s not even funny! 这显然违反了“simple things should be simple”原则。

[1] [2] [3] [4] [5]




标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇: 瘦身前后——兼谈C 语言进化[4]

下一篇: 瘦身前后——兼谈C 语言进化[5]

热门词条
热门标签