C 扩展对闭包特性的支持
今日听说某君批评 C 语言说它【输入一个参数返回一个函数】很困难。
例如在 Python 中,你可以
def addn(n):
def addx(x):
return n + x
return addx
my_adder = addn(42)
print(my_adder(21))
标准 C 要实现这样的功能也不是不可以,这是一个闭包的功能,我们只要显式的把上下文抓住就可以了。
#include <stdio.h>
typedef struct Adder { int n; } Adder;
Adder addn(int n) {
Adder addn;
addn.n = n;
return addn;
}
int apply(Adder addn, int x) { return addn.n + x; }
int main() {
Adder add42 = addn(42);
printf("%d\n", apply(add42, 21));
return 0;
}
这样的写法未免过于复杂,而闭包是现代程序设计里面很常用到的一种结构,面对更复杂的上下文,为了模拟闭包,所要做的比一个 Adder
结构体要多得多。对于这样常用的结构,主流的 C 编译器,即 gcc 和 clang 都提供了 C 扩展来支持这样的功能。
在 clang 中,你可以这样写
#include <stdio.h>
#include <Block.h>
int (^addn(int n))(int) {
__block int i = n;
return Block_copy( ^(int x) {
return x + n;
});
}
int main() {
int (^add42)(int) = addn(42);
printf("%d\n", add42(21));
return 0;
}
熟悉 Objective-C 的同学应该对 block 不陌生,这里 block 的类型名写起来比较麻烦,可以用 typedef int (^MyClosure)(int);
来定义更有可读性的类型名。
在 gcc 中,可以使用 nested functions 扩展
#include <stdio.h>
int (*addn(int n))(int) {
int addx(int x) {
return n + x;
}
return addx;
}
int main() {
int (*add42)(int) = addn(42);
printf("%d\n", add42(21));
return 0;
}
同样这里的函数指针也可以用 typedef 来定义一个可读的类型名。
这个问题在 C++ 中可以通过在类中重载括号运算符来实现。本质上是上面复杂代码所揭示出的捕获上下文并查看上下文信息的动作,现代语言为此封装了看起来像直接调用的简洁语法,使得代码更好写,更好读。
C 扩展对闭包特性的支持的更多相关文章
- 目前主流编译器对C++11特性的支持情况
目前主流编译器对C++11特性的支持情况 1. GCC编译器(从编译器GCC4.8.X的版本完全支持) (1)目前C++11特性,之前成为C++0X特性,从GCC4.3的后续版本中逐步对C++11进行 ...
- 深入理解JavaScript的闭包特性如何给循环中的对象添加事件
初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数中(event handler)获取对应的索引.但每次获取的都是最后一次循环的索引.原因是初学者并未理解JavaScript ...
- 快速入门系列--WCF--08扩展与新特性
最后一章将进行WCF扩展和新特性的学习,这部分内容有一定深度,有一个基本的了解即可,当需要自定义一个完整的SOA框架时,可以再进行细致的学习和实践. 服务端架构体系的构建主要包含接下来的几个要素:服务 ...
- Datagrid扩展方法onClickCell{easyui-datagrid-扩充-支持单元格编辑}
//-----------------------------------------------------------------/******************************** ...
- 如何给循环中的对象添加事件--深入理解JavaScript的闭包特性
初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数中(event handler)获取对应的索引.但每次获取的都是最后一次循环的索引.原因是初学者并未理解JavaScript ...
- 深入理解JavaScript的闭包特性 如何给循环中的对象添加事件(转载)
原文参考:http://blog.csdn.net/gaoshanwudi/article/details/7355794 初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数 ...
- JavaScript的闭包特性
闭包是一个比较抽象的概念,尤其是对js新手来说.在这里,我就我个人的理解j简单谈一下: 闭包:官方解释是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部 ...
- 从匿名函数(闭包特性)到 PHP 设计模式之容器模式
匿名函数(匿名函数) 匿名函数,也叫闭包函数,它允许临时创建一个没有指定名称的函数,常用作回调函数参数的值,也可以作为变量的值来使用.具体的使用见以下示例代码: /* 示例一:声明一个简单匿名函数,并 ...
- JavaScript快速检测浏览器对CSS3特性的支持情况
项目中使用动画效果在IE9下不支持,所以写了个判断浏览器是否支持动画的函数,进而扩展到下面判断浏览器支持任一特定CSS3属性的函数. function supportAnimation(){ var ...
随机推荐
- Mysql Atm取款机系统模拟案例
#创建ATM数据库 CREATE DATABASE ATM; #创建用户CREATE USER `ATMMaster` IDENTIFIED BY '1234';GRANT ALL ON ATM.* ...
- Hadoop MapReduce的Shuffle过程
一.概述 理解Hadoop的Shuffle过程是一个大数据工程师必须的,笔者自己将学习笔记记录下来,以便以后方便复习查看. 二. MapReduce确保每个reducer的输入都是按键排序的.系统执行 ...
- 【Python-Django】浏览器同源策略
1995年,同源政策由 Netscape 公司引入浏览器.目前,所有浏览器都实行这个政策. 同源策略是浏览器的一个安全功能,不同源的客户端脚本(js文件)在没有明确授权的情况下,不能读写对方资源.只有 ...
- 搭建nexus私服
一.安装 1.从网上下载nexus软件https://www.sonatype.com/download-oss-sonatype 下载Nexus Repository Manager OSS软件包 ...
- Socket编程:UDP和TCP概论及案例
网络编程的三要素: 1.IP地址 2.端口 3.协议 什么是Socket? Socket就是通信链路的端点称"套接词". 基于TCP协议的Socket网络通信: 用来实现双向安全 ...
- 制造资源计划(Manufacturing Resource Planning,Mrp II)
制造资源计划(Manufacturing Resource Planning,Mrp II) 概括: 以物料需求计划(MRP)为核心的企业生产管理计划系统,MRP II 是以工业工 ...
- ASP.NET Core MVC 之视图组件(View Component)
1.视图组件介绍 视图组件是 ASP.NET Core MVC 的新特性,类似于局部视图,但它更强大.视图组件不使用模型绑定,并且仅依赖于调用它时所提供的数据. 视图组件特点: 呈块状,而不是整个响应 ...
- Mybatis学习笔记之---环境搭建与入门
Mybatis环境搭建与入门 (一)环境搭建 (1)第一步:创建maven工程并导入jar包 <dependencies> <dependency> <groupId&g ...
- Thread、ThreadPool、Task、Parallel、Async和Await基本用法、区别以及弊端
多线程的操作在程序中也是比较常见的,比如开启一个线程执行一些比较耗时的操作(IO操作),而主线程继续执行当前操作,不会造成主线程阻塞.线程又分为前台线程和后台线程,区别是:整个程序必须要运行完前台线程 ...
- [Spring cloud 一步步实现广告系统] 2. 配置&Eureka服务
父项目管理 首先,我们在创建投放系统之前,先看一下我们的工程结构: mscx-ad-sponsor就是我们的广告投放系统.如上结构,我们需要首先创建一个Parent Project mscx-ad 来 ...