瘦身前后——兼谈C 语言进化[2]
2008-02-23 05:41:04来源:互联网 阅读 ()
先举一个平易近人的例子(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]
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash