可能你用过很多语言,也可能你对他们很熟悉,那么对于开发者而言,语言的底层技术是什么?
c是一个语言的最小集合,如果你去看最早一版的c教程《The C Programming Language》,你会发现它的几个特点:
- 最接近机器的语言
- 语言的最小+最全集合
其它的语言,比如:java,python,lua,php,都是在c语言的基础上构建起来的,当然,它们提供了更多的语言特性,比如:元数据、反射、容器等。
那么,c的核心是什么?大概是函数。
假设我们定义了2个函数:
void a() {…}
void b() {…}
单从需求上来讲,可以将函数拓展成lambda表达式、或者是右值(被赋值给某个变量)、当作某个类的方法(本质上也是函数,只是函数名称有它新的规则)。
如果考虑a 调用b,那么这个就会变得有趣:
a调用b 它是由3部分组成:a、调用、b(a和b都可以是一组函数、调用可以认为是引用)。
对于a,b而言,这里面有要分两种情况:
如果b先出现,比如:有一组接口实现字符串的接口,那么a直接参考接口文档,调用即可。
如果a先出现,比如:chrome浏览器,它是可以写插件的,它的方式就是插件必须按照某种方式来写(协议)才能被集成到chrome里面;spring boot 容器,如果想注入到spring boot 里面,必须使用注解注入,比如:@Bean,@Controller,@Service等。
本质上来讲,a能成功调用b,是遵循某种协议的,一点协议有了,其实a和b谁先出现都可以。若是没有协议,那么显然会变得有些复杂。这里面体现了接口协议设计的重要性。
对于调用来讲,就比较有意思了。你会发现调用这个操作上也能做手脚,变得复杂。调用只能被拦截(AOP),否则就会影响a 和b,给它们增加负担。
无论拦截做到a,还是b端,ab至少有一个是被自动加载的(假设加载者为容器,所谓自动加载,就是生命周期被托管,只有这样,ab的容器,才能对调用做手脚。
一般对调用做手脚,应用场景为:b调用前后的日志打印、调用b的性能监控等;这里面有几种方案:b上加注解(spring boot)、按b的名字的前后缀(测试用例),b所在的包名称等等,主要是基于b的属性找规律;如果是加注解,则需要语言支持反射功能(java很早就有反射功能,真是有远见)。
总之,现在你看到的很多语言的特性,都可以抽象为a调用b这个场景,只是复杂化了。