自学编程,从此开始

上第2学堂,听有趣的编程课

课文: 《你好,数据!(下)》 (点击查看完整内容:视频+评测+讨论+……)

作者:null

丁小明遇上财务总监,一不小心改了人家的姓!我们应该从中受到的教育:能const就const。

课文题图

 

第5节:你好,数据!(下)

0、这节课的重点理解约束,而不是“常量”

1、约束即自由

上一节提到数据的四个要素:名字、类型、值、址。

其中的值和址是数据的核心属性。因为它们几乎是与生俱来的客观存在;就像你家的抽屉,只是身为人家的抽屉,就得有个位置(地址),并且抽屉里就得有些内容,哪怕是空气——真空或许算是空值,但在计算机中,哪怕是空值,也得有个数据来表达,就像现在我在对你说“空值”,其实它一点也不空,它得占用两个字。

另外两个属性,名字和类型,却更多的是用来服务程序员(面向程序员),而非为机器(内存)服务。名字提供的服务很好理解,相比数据地址的一大串无意义的数字不好理解不好记忆,名字是可读的,易记的,可以有效地减少代码中张冠李戴的低级错误。再者,只要想想现实生活,也就能理解为什么要给数据取名字。除了在监狱里使用编号,我们一直在现实生活中一边拥有自己的名字, 一边也爱给别人取些更好记的外号。

最后是类型。事实上现实生活中的数据也一直有类型。我们通常一直在被别人明着地暗着地划分类型,也一直在对别人明着的暗着地划分类型。我就看到有个家伙的QQ好友是这么分类的:“上不了的”,“努力一把或可上的”,“已上过的”……这太过份的了;换个实际例子。我又有次在某个下属的通信录中,看到一个大分组:领导组;然后下面是“有点本事但阴阳怪气的”、“没什么本事但和蔼可亲的”、“没什么本事还阴阳怪气的”……就在我走过去的一瞬间,我看到她迅速地合上最后一页……

尽是些可怕的,而且负面的例子。让我说来些阳光点的,至少得是客观中性的案例。

我教学大家学编程,自然就会有一时学得比较慢的,此时我当然是鼓励居多,但偶尔也会急了要批评。经历的多了,我有了一个重大发现:批评一个学生:“你真笨!”,口气再凶,他最多不高兴,也不会和我急;但如果我说一句:“你还是人吗?”、或者“你是猪吧?”,哪怕轻描淡写,多数人都会怒而反怼我。这种经历几乎人人都有过,没什么大不了。真正伟大的发现是:人类有一种与生俱来的防备:不喜欢被别人乱扣类型,更不喜欢被乱改类型。这还没完,我为此购买了好几本心理学书,继续深挖,终于悟出,每个人作为社会个体,其实天生就有喜欢加入分类的需要……

非常复杂,不展开了。总之,记住:对一个数据最恶毒的置疑、否定、攻击,就是置疑、否定、攻击它的类型。骂一个男人,最狠的就是“你还算是个男人吗?”。重点是背后道理:类型约定了数据的内部结构、约定了数据对外的行为举止、约定了数据能做什么不能做什么。所以否定一个男人不是男人,就是在否定这个男人不能做一个男人本应能做的某些事,或者做了一个男人本不应该做的某些事。是挺狠毒的。

内存中以致硬盘上各类数据,其实都是一大串0和1的各种组合。如果它有一个".mp3"的文件,里面的数据就被划分成“音乐”,于是它就应该可以被播放出声音。而一个有着“.jpg”的文件,如果你对它大叫一声“你还算是首歌曲吗?”,或者,“你是一首歌吗?”。倘若它有感情,它一定伤心欲绝。天若有情天亦老,就是因为天底下有太多人曾经对它绝望地骂过:“苍天,你算个屁啊!”。

我们不会抬头看见天就捂鼻子。我们也不会真拿着一张jpg的图逼着网易云音乐将它播放出声音。正是数据约定的类型,提示、限制、约束我们对数据做出搞错类型的,可怕的错乱行为。搞错名字只不过是张冠李戴,搞错类型——“这是马?还是鹿?”,赵高在问我们。

内存中的数据本无类型,只是正巧我们所学的C++编程语言是现实主义派,所以在C++的语法系统中对数据做了“强类型”约束。两个int类型的数据,可以加减乘除、但两个std::string的数据,就只能相加(拼接),其余是没有意义并且不可操作的:

5 - 2; //OK
5 * 2; //OK
5 / 2; //OK

"丁小明" - "张二妞"; //什么鬼操作?
"丁小明" * "张二妞"; //什么鬼操作?
"丁小明" / "张二妞"; //什么鬼操作?

当我们以“操作”为中心——称为“面向过程”——那么就说 “某某操作无法施加在某某类型的数据身上”。比如:"相除操作无法施加在两个字符串身上"。而当我以“数据”为中心——所以称为“面向对象”(记住:数据、对象、东西经常是一个概念)——那么就说:“某某类型的对象,不具备某些操作的能力”。是什么约束了数据的能力?是类型。还是太负面了,换个阳光的说法:“类型赋予了数据既定的能力”。

有了类型,程序中的所有数据就有了清晰功能边界。程序员们用起来放心了许多,因为一旦搞错,通常C++编译器会帮我们指出来。这是“强类型”编程语言带给我们的好处。当然也可以说是坏处:我们哪怕在C++代码的世界里,也和在俗世一样平凡:我们无法将一只青蛙变成一个王子。在某些语言里,这是毫无问题的魔法。但因为我们是C++程序员,而C++程序员必须是成年人,而成年人最主要标志,就是懂是:这个世界不能没有童话,但这个世界更应该认清现实。

约束即自由。

2、CONST

除了使用类型来死死限定我们乱处理数据之外,“CONST”这个表示“恒定的、不变的”词,在C++中,既可以像本节所讲的常量那样用来限定一个数据不可变,也可以限定某个行为不能修改某些数据。古人云:“由俭入奢易、由奢入俭难”。C++程序员则说:“由不变变到变易,由变变到不变难”。将来总有一天大家会发现,身为一个C++程序员,“自我约束”简直就是编程的黄金教条;而其中“能用常量就用常量”是一种被广泛实践应用的原则。

成年人不应该是非常自由的吗?怎么像小孩子一样这不能做?那不能做?这样理解是错误的哦!当我们成年人的”能“或”不能“时,更多的不是指能力;而是指懂得”懂“或”不懂“。成年人懂不要去沾毒;成年人懂不要去烟花柳巷;成年人懂不要观赌;成年人懂不要一天倦曲在床上看手机;成年人懂不要暴饮暴食;成年人懂要和优秀的人有来往,少和垃圾人接触;成年人懂得至少学一门底层的语言才有可能成为技术大牛,别混想有什么轻轻松松学会还轻轻松松让你月入2万的什么最牛叉的编程语言……

设计大师说:“若无必要,勿增实体。” 编程大师告诉我们:若无必要,不要引入变化,哪怕是潜在的变化。你先约定某个数据不能变化,直到被逼到你反复思考之后,还是认为它确实必须可变再变。这一过程中,无论是发现问题,还是发现问题以后的改动,都是轻松的;但反过来,肆无忌惮地变动各个数据,就容易限入不知哪个数据在哪个地方哪个时间下改错了哪个值的情况,发现以后要改,通常也会限入牵一发而动全身的困局。

视频课程中丁小明修改了被问候人的姓名,只是一个简单的、搞笑的例子。但程序员长着肉身,还经常生物钟混乱。想想这样一大堆人组成一个团队开发软件……你调用我写的函数,我调用你写的函数……到处修改数据……不受约束……世界上几乎最复杂的团队软件都是强类型语言,比如C++写出来,是有道理的,因为可信赖。我给你一个名字,让你问候,我知道,除非你心智全疯,否则哪怕是你喝高,也不会去动这个名字——当然不是完全相信你的人品,而是相信const对你的约束。

3、小细节:const的位置

定义一个常量双精度数,值为3.14,我们推荐写法以及读法(见注释)是:

double const pai = 3.14; //一个双精度数,并且是常量

但你在现有的代码或别的课程中,更多的可能是看到这样的定义:

const double pai = 3.14; //一个常量的双精度数

即,const放在类型的前面。请理解后面这种写法,但在写时,请坚持使用我们推荐的写法。两个主要理由:

  1. 将来引入指针等知识点后,const 到底在限定什么时,使用我们写法,更容易理解。
  2. 相比const,类型其实是更重要的数据信息和限定。放在前面更容易注意到。

3、源代码

#include <iostream>
#include <string>

using namespace std;

void Hello(string const name)
{
    cout << "你好," << name << "!" <<endl;
}

//问对方名字
string WhatIsYourName()
{
    cout << "您好,我是丁小明,请问您是?" << endl;
    cout << "我是:";

    string name;
    cin >> name; //从键盘得到输入内容

    return name;
}

int main()
{
    Hello("林总");
    Hello("张大师");

    string name = WhatIsYourName();
    Hello(name);

    string name = WhatIsYourName();
    Hello(name);

    return 0;
}