随便说说--编程到底该学什么
[00:21.100]過去未来…世界中で時巡る [00:21.100]从过去到未来在世界中巡回 [00:27.490]だけど今ここを選んでた [00:27.490]但现在选择了这 [00:33.350]幾つの道もこの場所に続いていた [00:33.350]有多少条路多少个地方但只想待在这里 [00:40.150]そう思えるんだ [00:40.150]至少我是那么想的 [00:45.100]高い秋の空見上げて [00:45.100]仰望着秋天那高高的天空 [00:50.450]ポツリ 立ち止まって駆られた [00:50.450](滴答) 微弱的风总是温柔的 [00:57.400]優しい風がいつだって [00:57.400]时而立定停下时而驱动着我 [01:02.350]この背中押し続けてたんだ… [01:02.350]在背后持续的推着我前进 [01:13.100]ありがとう [01:13.100]谢谢你 [01:16.100]ありがとう [01:16.100]谢谢你 [01:20.100]ねぇ 明日迎えるって奇跡 [01:20.100]让我能够迎向明日的奇迹 [01:25.100]ごめんね、帰らないよ [01:25.100]但对不起 我回不去了 [01:33.480]僕らいつでも前を見てるから… [01:33.480]因为我们只能一直向前看 [01:42.150]手の中に一つ握ったピース [01:42.150]紧握着在手中唯一的和平 [01:48.480]誰もかパズルの欠片を合わせて [01:48.480]谁能谜题的碎片重新组合起来 [01:55.100]叶わない夢も叶えられる [01:55.100]如同把不能实现的梦实现 [02:03.350]そう願いながら [02:03.350]但仍旧这样祈祷着 [02:06.490]あの日少しだけ無理して [02:06.490]那一天勉强着自己 [02:13.490]ホロリ 零れた涙の粒(つぶ)を [02:13.490](滴答) 所落下来的眼泪 [02:20.050]素直な心に包んで [02:20.050]被直率的心给包围着 [02:23.450]もう一度歩き出したいんだ… [02:23.450]使我想在一次走下去 [02:35.250]さよなら [02:35.250]再见了 [02:38.250]さよなら [02:38.250]再见了 [02:42.350]そう もっと笑顔が見たくて [02:42.350]还想更多的看着你的笑容 [02:48.250]だからね 迷わないよ [02:48.250]所以了 别迷惘 [02:56.100]僕らいつでも前を見てるから [02:56.100]因为我们无时无刻都在向前看 [03:31.450]ありがとう [03:31.450]谢谢你 [03:35.100]ありがとう [03:35.100]谢谢你 [03:39.050]ねぇ この気持ち届けたくて [03:39.050]很想传达给你这份感情 [03:44.450]昨日に迷わないよ [03:44.450]但被昨日给迷惑住 [03:51.450]With a thankful heart [03:51.450]with a thankful heart [04:00.450]ありがとう [04:00.450]谢谢你 [04:03.100]ありがとう [04:03.100]谢谢你 [04:07.120]ねぇ 明日迎えるって奇跡 [04:07.120]让我能够迎向明日的奇迹 [04:12.480]ごめんね、帰らないよ [04:12.480]但对不起我回不去了 [04:21.120]僕らいつでも前を見てるから… [04:21.120]因为我们只能一直向前看
因为没有课题,所以这次讲点浅薄的实践经验。
我自诩作为一个精通数学框架、学过多种编程语言、探究过多种程序框架的人,想就自己的经验来讲点无用的废话。先说一下所谓的学过,指的就是大众所了解的系统学习,即找一个课程,从头学到尾,并完成相应的练习或demo。接下来要做的百分之百是免责申明,但套路大家都懂,我也懒得说,一句“个人经验,仅供参考”就足矣了。最后,我将主要讨论的是软件程序相关的内容,至于数学留在心中即可。
以目的为导向。学一样东西之前,想清目的是十分重要的,如今的世界是一个知识过剩的时代,以贪婪的心态将其全部收入囊中是不可取的,其最后只会反噬自己,根据需求用合适的精力和时间学习合适的东西是最好的选择。如果你没有明确的目的,只是想学习编程的话,那我推荐你跟我一样向着程序大佬迈进吧。什么是程序大佬?反正我肯定不是。想要成为大佬的第一步是“兴趣十足,热爱学习”,你可以反感应试反感形式主义,但反感学习拒绝接受新知识绝对是失败的开始。想成为大佬的第二步是“拥有足够可信的知识源”,简单来说就是,你需要有强大的信息检索、分辨过滤、系统整理等能力,并且能找到验证信息真实性的方法。这类东西主要靠培养和多实践,并不存在太多理论性的东西。想成为大佬的第三步是“理论与应用相结合”,一个十分简单的方法就是,多提问,对于设想的场景,直接编程验证,并思考原因。很多时候,一次可能查不出原因,但多改变条件、多改变层次,在理解一些东西的基础上,都是可以独自探究出来的。这都是经验之谈,而需要了解的基础是我接下来讨论的东西,是迈向程序大佬的基本修养。
请学C/C++。将C/C++放在一起的理由不必多说,后面为了方便就直接称为C语言了。学习C语言的目的并一定是为了应用它,而是通过学习C语言来亲近计算机系统,以便在理解其它编程语言时变得更加游刃有余。在C语言的编译过程,一方面可以提升自己的折腾能力,而借助这股耐心之力对我们以后调试除错具有极大的帮助,另一方面,C语言的编译过程“预处理->编译->汇编->链接”,展示了亲近机器码的一面,其可以加深我们以后搞反汇编和进行程序破解时对程序运行机制的理解。实际上,我们需要对诸多语言有个清醒的认识,在系统层面上,几乎所有的操作系统都有着C语言的原生支持,当然只论静态编译成CPU指令的语言并不只有C语言,比如rust、go等都可以做到,至于需要运行时环境的语言就不要考虑了,因为此时你亲近的是虚拟机,而不是操作系统,而虚拟机的编写最后还是要回归的亲近操作系统上来。所以单纯说C语言是高性能吧,其实还是有不少替代的。
玩转内存管理。要说学C语言的最大意义吧,那就是学会内存的管理,体验被内存问题支配的恐惧。内存问题是多方面的,比如内存溢出吧,如果放到一般场景下,最容易产生这类问题的就是大文件的读取,比如读取一个视频吧,没有内存管理经验的人,就会不自觉地将文件全部读入,然后再进行解码,而这些全在内存中进行的话,区区几G的运行内存还真不够用。当然现在是一个轮子遍地的时代,也没有谁会去单独开发新的解码库了。当然内存管理也不仅仅是内存上的问题,还有指针,将指针和引用玩得炉火纯青的一个大前提就是,你需要对程序运行时的内存布局有个十分清醒的认识,不然一不小心就会引发,指向一个不可读取区域的错误。
抛弃面向对象的思想。虽然C++确实有类的概念,我也更推荐去使用类,但我们要知道在C++里类和结构体是几乎没有区别的,我们应该以结构体的思想去看待类,也就是说将类或对象看成一种结构化的数据管理方式,而管理的数据是成员变量和成员函数。这种思想并不罕见,你可以在js、lua或python(如数家珍的几个常用脚本语言)等各种脚本语言中找到这种思想,程序本质上只有面向过程,由变量、函数和传参组成整个运行流程,所谓的面向对象实际就是一个类对象变量this(在python和lua中是self),在各函数之间的传参而已。在对象数据管理机制中,一个重要的东西是读取权限(诸如private、public等),当然我们知道它在编译时生效,当程序处于运行状态时,完全可以通过hook搞到手,但是其对模块化编程有着极大的作用,我们可以通过权限看到哪些是对外有影响的模块,从而更好地调整程序。典型没有权限管理的例子javascript之前的版本,现在倒是几乎所有的语言都有权限访问修饰符了。如果你觉得我这样相当于抛弃了继承、多态、抽象类等重要概念的话(动态多态?),不如先看看我所说的“思想”的含义,然后你再多实践一下大概就能理解了。
把握数据的流动。程序的本质是面向过程、数据和线程的。所谓数据包含变量、函数、内存和文件,对于一个变量所指向的数据,你需要懂得它的表象和实在,所谓表象就是它在程序中的含义,比如int是一个有符号整数,而它的实在是一个4字节的二进制数据,至于保存在哪则需要看情况。如果是在函数中直接声明的,则其处于函数运行的栈内存中。如果声明在函数外,作为全局变量的话,则会存放在程序的静态变量区中。还有一种更离谱的来源,就是通过new或malloc声明内存后再强制类型转化为int,此时它就存放在堆内存中。这其实挺像内存管理的玩意,但不仅如此,数据流动的另一个重点是等号赋值。如果一种数据不存在等号重载的话,那么能直接传递数值的只有C语言内置的几种数据类型,诸如char,int或指针之类的,指针本质上是一个无符号int数据类型,用于保存数据的首地址,而指针带上类型大多都是用来方便加减操作罢了,这就是数据类型的识本。实际上,有些开发中,比如QT,你为了安全性基本只能采用其提供的数据类型,而QT借用的也只是语法而已,此时认识数据流动的轨迹也应该转化为QT的思维。
边用边学。系统学习虽然好,我们甚至可以一次性学习标准模板类、文件系统、网络协议、线程并发、数据库、多媒体等各种场景的API,但你只要一段时间不用,过不了多久就会全部忘光(警防API式教程陷阱)。既然如此不然从一开始就只是知道有这么一会事就行了,我们并非处于一个没通网的封闭社会,我们也并非没有阅读文档的能力,其实更重要的一点是,软件技术是不断发展的,API是会随着时间的推移而改变的。单纯学习API,不如去了解API的由来和原理,这样不仅能提高我们运用API的能力,和让我们拥有了改造API的可能性。边用边学的核心理念就是,“需要是再找,用多自然熟”,当然如果你没有可以开发运用的项目,也可以去阅读优秀大型开源项目的源码,达到边看边学的境界。如果你说读不懂,只能说这是因为你不想读而导致内心产生了的畏惧,这时你需要先把前面的内容搞通透,并锻炼出不怕bug且以解决bug为冒险闯关的心态,时间可以解决一切。
模块管理。此处是扩展内容,和我之前讲过的文件管理有类似之处,C语言的模块管理或者说包管理,就是一个讨论如何应用第三方API的问题。请注意模块管理的问题不在于模块管理工具的选择,而在于实际应用中,比如选择静态库还是动态库,如何解决两个库直接存在冲突依赖的问题等等。最好的办法是少用依赖,这不是废话吗?懒惰的办法就是加命名空间。你跟我说最新C++标准?可问题是我需要的库,它也采用相同的标准才行,反正真要翻新也不是一时半会的时,而且以我个人来看很多新C++标准就是简化编程用的,很多事情旧标准也同样做得到,而且有时可读性还会更高一些,没有可读性的话,还真不配被称为高级语言。少用库的前提就是,你要搞懂库到底为你做了什么,一些能自己实现的东西,自己搞定就完事了,而需要依赖系统API的那也是没办法的事。另外,headerOnly在我看来是个不值得推崇的坏习惯,要知道编译冲突的根源就是函数重名,在反复引入时还得整一套复杂的剔除机制,只能说难受。当然引发headerOnly的根本原因之一是模板template,模板本质是一种用于代码简化的产物,虽然很多人喜欢将其视为C++的精髓之一,但我提议能别用就别用,当然你就是想用就随便了。
结束吧。其实本来我是想将经验写成一本书的,但仔细想想我自己是一个没有任何项目经历的菜鸡,就还是算了吧。而且还有一个原因是,编程搞久了自然就会调教出自己的一套方法论,这是最实在的东西,“与其说上千百遍,不如多摔跤几次”。不过嘛,还想说一句老生常谈的东西,“想尽一切办法去搞清原理,不要只做掉包侠。”……嗯……有的人只想当掉API侠那也没办法。