编程语言“破剑式”——编程语言学什么?

摘要:C/C++稳如磐石,Java依然如日中天,Python正迅速崛起,大有成为新王者的趋势,三分天下各有其一。前端开发的语言有JavaScript、TypeScript,Android开发有Kotlin、iOS开发有Swift……,还有Go、Erlang、Scala、Lua、Groovy……等,是否真有人能熟练使用它们?或者说是否有人能迅速在各种编程语言之间自由切换?这样的人到底是传说?还是真实存在的?本文肯定地告诉你这种人是真实存在的,而且会告诉你这种人所掌握的总诀。本文揭示的是编程语言的“破剑式”,不针对任何特定的语言。

海风教育在线辅导0元一对一试听课等你来领取,领取课程方法:
1、私信留下您的手机号和姓名,需要补习的科目。
2、也可以在海风教育官网留下您的手机号领取 https://www.hfjy.com

多年来,我背负了一些的误解:有人骂我,觉得我会的编程语言太多,肯定是抄别人的,只是找不到被我抄的东西在哪里!反倒是我最近刚刚收到起诉清华大学出版社侵权胜诉的判决书:

也有人觉得:李刚不是一个人,李刚是一个团队,由于很多人写书都署名为李刚,所以看上去他似乎掌握了这么多编程技术。本文也向大家保证:只要图书上署名“李刚”的、且以本人头像作为封面的图书,都是我亲笔创作的,没有什么团队代笔的事。

如果你能接受我可以能熟练(此处不说精通)使用近20种编程语言的事实,那你可以继续阅读下文;如果你觉得我完全就是吹牛B,那你就没必要阅读下去了。本文试图向你揭示编程语言的总诀,一旦你真正掌握编程语言的这个总诀后,你将能迅速使用各种编程语言。

开车的感悟

这里说的开车,真的就是驾驶汽车!对于初学开车的司机来说,汽车是充满神秘的(至少我刚学开车时有这种感觉):那么多的按钮,那么多踏板,那么多拨杆,初学者往往手都不知道放哪儿。

反过来,对于多年的老司机来说,不管他坐在一台什么品牌、什么型号的汽车里面,他都可以立即开车上路,不需要再针对特定汽车重新学车,这是为什么呢?关键就在于老司机知道他需要掌握汽车哪些地方:
如何点火?钥匙也好,无钥匙也好,老司机坐上车第一件事就是想如何点火。
如何换挡?无论是否有离合,无论变速杆的位置怎么摆放,他接下来想到的就是如何换挡。
如何加油?转向灯如何打开?雨刮如何如何打开?雾灯如何开启?空调如何开启?……

总之,老司机是根据汽车本身的组成去“学习开车”,换句话来说,他很清楚汽车必须有这些功能,否则它就不是一辆汽车。与此类似,功力深厚的开发者学习一门编程语言时,不会被编程语言本身看似纷繁芜杂的表面所迷惑,同样也会根据编程语言本身的组成去“学习编程”,他们很清楚编程语言必须有这些功能,否则它就不是一门编程语言。

下面就详细介绍一门编程语言必须(应该)包含哪些东西——就像一台汽车必须包含哪些功能一样——当你学习任何编程语言时,你只要很清楚一门编程语言本身的组成,这样学习一门编程语言就是非常迅速。

从数据开始——变量、数据类型、数组(或类数组)

IT、IT,I是根本,T是手段,因此编程的本质就是对数据的处理。在程序里,数据就是放在变量中保存的,因此无论学习何种编程语言,首先要学习的一定是变量。
形象上来说,变量就是相当于一个日常的小容器,日常的小容器可用来装东西,但变量则用来装数据。

容器 = 变量

学习变量时,需要区分目前编程界有两种主流的编程语言:
强类型语言:这类编程语言有两个特征:①、所有变量必须先声明、后使用;②、特定类型的变量只能特定类型的数据;也就是说,定义变量时声明它为什么类型,那么它以后将永远是什么类型。
弱类型语言:这类编程语言有两个特征:①、变量无需声明,即可立即使用;②、变量没有类型,因此变量在不同时间点可能装不同类型的数据。
掌握了这两点之后,开发者其实完全可以自行判断一门语言是强类型语言,还是弱类型的语言!不要因为听到某某所谓“大牛”的说法、或网络上流传某些说法影响了自己的判断。

但无论变量是否有类型(强类型的语言变量有类型,弱类型的语言变量没有类型),但数据总是有类型的,因此学习变量时肯定伴随着学习各种数据类型。
比如Java的数据可分为基本类型(8个基本类型)和引用类型(数组、类、接口和枚举);Python的数据类型则都是Python的内置类(如int、float、str、list、tuple等)。

定义变量

不同语言定义变量的语法不同。通常来说,强类型语言的变量必须先定义,后使用,因此通常需要掌握定义变量的语法;弱类型语言的变量往往无需先定义,通常是第一次对不存在的变量赋值时就定义了该变量。因此,定义变量这个语法,通常都是针对强类型的语言的。

早期的强类型语言通常采用如下语法格式定义变量:

类型 变量名 [= 初始值]

现在新出现的强类型的语言流行使用var来定义变量,比如Swift、Kotlin等,甚至Java 10也开始支持使用var定义变量。

使用var定义变量的强类型语言都支持一个特性:变量类型推断。所谓“变量类型推断”,指的是编译器会根据程序对变量所赋的初始值来推断变量的类型——因此该变量还是有固定的类型;

通常来说,使用var定义变量时支持两种语法:
变量类型推断:使用方式定义变量时必须指定初始值,这样系统才能根据初始值的类型来推断出变量的类型。
显式指定类型:这种方式可以指定初始值,它通常会在变量后面用冒号加类型的方式来显式声明变量的类型。
总结起来,使用var定义变量的语法如下:

var 变量名 [: 类型] [ = 初始值]

在上面语法格式中,要么通过[: 类型]显式指定变量的类型,要么通过[ = 初始值]为变量指定初始值,这样编译器可推断该变量的类型,不能仅使用“var 变量名”这种方式来定义变量——因为这样无法确定变量的类型。

学习变量除了掌握定义变量的语法之外,重点是掌握变量的分类:程序在不同位置定义变量,变量的类型会有不同:局部变量、代码块内的局部变量、实例变量、类变量、全局变量……不同变量在内存中的存储位置不同,它们的生存期限也不同;不同类型的变量是否可以同名?程序如何区分同名的变量?这些需要开发者仔细体会——基本上一门语言认真掌握一次之后,大部分语言都有类似的地方。所以我的建议是:“深度优先、广度补足”——首先认真“精研”一门编程语言中各种变量的内存存储机制,再去看其他编程语言的变量的内存存储机制会很容易。

变量赋值、数值计算

定义完变量之后,自然就需要对变量赋值了。如果把变量当成一个容器,那对变量赋值的过程,就相当于把数据放入容器的过程。通常来说,大部分语言赋值运算符都是等号(=),但有少数语言的赋值运算符是冒号等号(:=)。

被赋的值除了可以是各种直接量(比如2、3.4、“fkjava”)之外,更多的则是表达式,因此各种语言都需要提供功能丰富的运算符。归纳来说,不同语言提供的运算符大致会包含如下几类:
算术运算符:+、-、*、**、/、%、++、–
位运算符:&、|、^、~、<<、>>、>>>
赋值运算符及扩展的赋值运算符
比较运算符:>、<、>=、<=、==(有的语言用=)、!=(有的语言用<>)
逻辑运算符:&&(有些语言支持不短路与)、||(有些语言支持不短路或)、!
范围运算符:… 、…<等,有些语言需使用range函数定义范围
三目运算符: ? :(有的语言使用if表达式代替三目运算符)
空值运算符:主要用于对null(或nil)进行简化判断、处理。
类型强转运算符

不同运算符有不同的优先级,而且运算符在运算时可能导致隐式的类型转换、数据溢出等——不同语言的溢出规则不同——有些语言甚至对运算符做了区分:分为溢出运算符和非溢出运算符,这样用起来更加安全。
无论如何,开发者使用一门语言的运算符时,务必注意隐式的类型转换和溢出这两个“坑”,这样开发者即使使用一门全新的语言也能做到有的放矢。

数组(或类数组)

普通变量只能保存单个的数据,当程序中有多个类型相同、功能类似的数据需要保存时,直接定义多个变量来保存它们,显然并不合适,原因有二:
在程序中定义多个类型相同、功能类似的变量显得非常臃肿。
编程时管理多个变量十分不方便。

此时的解决方案就是数组(类数组)——由此可见,引入数组(或类数组)的动机就是保存多个类型相同、功能类似的变量,因此数组元素的用法就相当于普通变量的用法。

形象上来看,数组其实就像一个“竹子”,“竹子”的每一节都可以保存一个东西,因此数组的每个元素都相当于一个变量,可以保存一个数据。

数组的形象

有些语言直接使用列表代替数组(比如Python),也有些语言使用数组代替列表(比如JavaScript)。虽然它们的名称上存在差异,但它们的功能其实是相同的,只是用法上存在一些细微差异:一般来说,列表(List)的长度是可变的,程序可以向列表中添加元素、也可以删除列表中的元素;但数组的长度通常是固定的(JavaScript数组完全可作为列表使用,因此JavaScript数组的长度也是可变的)。

学习数组要认真体会以下几点:
创建数组(或类数组)的语法
获取数组(或类数组)长度的方法
如果使用List代替数组,如何对List添加、删除、替换元素。
访问数组(或类数组)元素的方式(正向访问、反向访问)、数组(或类数组)索引何时越界?
数组(或类数组)元素在内存中存储方式:是否连续存储?是否支持指针计算?
多维数组(或类数组)是否真的存在?多维数组(或类数组)的本质是什么?

程序执行——流程控制

流程控制是所有编程语言的基础,现代编程语言基本都提供了以下三种流程:
顺序结构
分支结构
循环结构

因此当开发者拿到一门语言时,二话不说肯定先得掌握这门语言的流程控制语法。一般来说,顺序结构没啥好说,反正程序默认就是从程序入口开始,顺序向下执行——也就是说,如果你不使用任何控制,那么程序流程默认就是顺序执行的。

分支结构通常可包含两种分支:
if分支
switch分支

基本上所有语言的if分支都差不多,无非就是由if、else if(有的写成elseif,有的写成elif…)、else组成。但由于分支总要控制代码块的执行,而不同语言对代码块的控制略有差异,因此它们各自的区别主要体现在代码块的区别上,常见有方式来控制代码块:
花括号控制代码块(以C、Java为代表)
用end if(有的语言也写成endif或fi等)等关键字控制代码块的结束(以Ruby等为代表)
以统一的缩进代表一个代码块(如Python为代表)

switch(有的语言叫case分支)通常用于对表达式的值进行判断,有的语言的switch分支只支持精确匹配(比如Java)、不支持范围;但有的语言的的switch分支支持范围匹配(如Swift)。

循环结构通常可分为:
while循环
do while循环
传统for循环
for each循环
until循环(少数语言支持这种循环)

与分支结构类似,基本上所有语言的循环结构大多差不多,通常只是对代码块的区分存在一些差异(有的用花括号,有的用关键字,有的通过缩进来区分),因此只要精研了一门语言的循环结构,其他语言的循环结构自然就一通百通了。

为了更灵活地控制循环结构,很多编程语言都会提供如下两个关键字:
break:用于结束、并跳出当前循环。某些语言(如Java等)还支持在break后带标签,这样该break可用于结束、并跳出标签所代表的循环。
continue:用于忽略当前循环剩下的语句,重新开始执行下一次循环。某些语言(如Java等)还支持在continue后带标签,这样该continue可用于忽略标签所代表的循环剩下的语句,重新开始执行下一次循环。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值