[00:00.000]作词 : 瀧沢一留
[00:01.000]作曲 : 八乙女葦菜
[00:21.262]導かれるように この道を辿った
[00:21.262]冥冥中谁在远方 引我沿此路前行
[00:29.876]閉ざされた世界は まだまどろみ
[00:29.876]禁闭无光的世界 依然沉睡不曾醒
[00:38.555]懐かしく痛む この胸に残る绊
[00:38.555]令人怀念的痛楚 心中残存的牵挂
[00:47.182]あなたの面影 ずっと探していた
[00:47.182]总让我不断探寻 你那熟悉的容颜
[00:53.914]欠けた月が(月は)
[00:53.914]夜空之中 明月高悬
[00:57.076]夜ごと満ちては消える(思い出すよう)
[00:57.076]月满盈亏难以捉摸 就如同回忆的过程
[01:03.287]触れるたひ(赤い)
[01:03.287]渴望伸手去触摸 天边的赤色晚霞
[01:05.491]鲜明に(痛み)重なって
[01:05.491]却感到清晰的痛苦 在心中缓缓堆积
[01:13.925]繰り返す赤き血の運命(さだめ)
[01:13.925]循环往复着的血色命运
[01:18.184]はじまりの予感に沈みゆく
[01:18.184]渐渐沉没于最初的预感
[01:22.261]今はふたり黄昏の中
[01:22.261]如今 我们相遇于黄昏时分
[01:27.008]夢の続きを教えて
[01:27.008]能否告诉我 那场梦的续篇
[01:36.573]水镜浮ぶ 在りし日の泡沫
[01:36.573]水面空灵如镜 摇曳着昔日的泡沫
[01:45.034]響きあう心は まだ戸惑い
[01:45.034]响彻着的心灵 依旧无比疑惑
[01:53.592]夜空に消えゆく 月へ返る蝶の群れ
[01:53.592]夜空中蝶群婆娑 渐渐消散在月旁
[02:02.008]遮る哀しみ 遠く渗ませていく
[02:02.008]这剪影般的哀伤 恍若浸没着远方
[02:08.920]満ちる月に(月に)
[02:08.920]满月的光芒
[02:12.180]照らされたふたつの影が(溶け合う)
[02:12.180]照耀出的两个身影 朦胧之中融为一体
[02:18.368]届かない(今は)未来を
[02:18.368]模糊的愿望 此刻难以传递到未来
[02:21.861](過去を)見诘め合う
[02:21.861]只好回首往昔继续找寻答案
[02:29.094]廻り逢ういのちの道筋
[02:29.094]偶然中踏上了命运的道路
[02:33.290]全てを知ってこの手を取れる?
[02:33.290]但就算是通晓一切 梦想依旧遥不可及
[02:37.712]踌躇いも痛みも抱き留め
[02:37.712]即便是迷茫与痛苦 亦是珍贵人生财富
[02:42.283]夢の続きを闘う
[02:42.283]为了延续梦想 勇敢踏上征途
[03:24.836]繰り返す赤き血の咎め
[03:24.836]血红色的斥责循环而往复
[03:29.142]抗えぬ終を示しても
[03:29.142]或许是因为抗争从未结束
[03:33.445]まだ見えぬ朝は迷わず
[03:33.445]未来虽不可测 却也不必迷茫
[03:38.097]あなたの傍に在りたい
[03:38.097]渴望在你身旁 顿觉势不可挡
[03:46.100]廻り逢ういのちの往く果て
[03:46.100]偶然中探寻到生命的结果
[03:50.423]重ねた手强く握り返す
[03:50.423]此间珍贵必将用双手紧握
[03:54.792]信じるもの守リ生きていく
[03:54.792]为了守护信仰 扼住命运喉咙
[03:59.444]夢の続きを 今あなたとふたり 誓うの
[03:59.444]只愿延续梦想 你我一同立下誓言
[04:13.054]約束の続き この夏の終わりに
[04:13.054]两人的约定 在这个夏末决不停息

语言无优劣之言,一切都只是选择罢了。而且更重要的是你做了什么,而这也是我最忏愧的东西。

在静态编译语言中,可以直接编译成cpu汇编指令的语言中,比较流行的主要有三种c/c++、rust、go。而另一方面,它们又是三种内存管理机制的典型代表,go语言采用大多数依靠虚拟运行时环境的高级语言的GC机制,这种东西虽然可以有各种意想不到的创新,但终究还是少见多怪,没啥好说的。而我真正想讨论的,是近些年的新起之秀Rust。
Rust有两大自豪的特性,高效和安全,这两种特性其实是可以分别实现的,因此rust的特性可以总结成一点“高效的内存安全型语言。”对此我们需要稍微讨论一下这两个词语的含义,在程序运行上,所谓“高效”指的就是速度快,它可以从两个方面进行提示,一是硬件换新,这没啥讨论的必要,因此另一方面就是从软件上减少指令执行的次数,其又存在两种方法,一是对指令进行优化缩减,而这正是编译理论及Release与Debug的关键区分点,大多数静态编译语言是大差不差的,而另一种则是减少指令的传递次数,比如依赖各种虚拟运行时环境的,在大多数情况下必定是比不上直接运行cpu指令的静态编译的语言,或许有些不严谨,在操作系统上,直接让cpu执行指令并不现实,执行汇编指令的时候往往都要经过操作系统这道坎,但只要我们还在操作系统上,这已经是能减少指令传递次数的极致了。因此我并不认为高效是rust的核心特性之一,实际上,在我的rust学习书《Rust圣经(Rust Course)》中,也只会说像“Rust 与 C++ 的性能旗鼓相当”这样保守的话。还需说明的一点是,go语言存在后台gc的守护线程,它会让程序运行稍微多一些开销,或许挺微小的,但我们正因如此,才不会把go纳入讨论之中。
由此看来,Rust最自豪的特性的重心应该落在内存安全上。所谓内存安全是啥呢?无非也是三点,没释放的内存导致内存溢出,释放的内存导致空引用,越界访问导致内存泄露。稍微学习一下rust我们就能知道,rust主要是依靠三大核心机制(所有权、借用和生命周期)来实现在编译阶段防止前两种情况的发生,而内存泄露理论上不属于语言该解决的问题,就像大部分理性者认为的,rust只是因为其特殊的机制可以减少写出内存泄露代码的风险。关于rust保证内存安全的三大机制,任何一本rust相关书都可以学,所以就懒得讲了,实际上,除去内存安全机制外,rust最让我羡慕的还是它的“Macro 宏编程”,说实话,到现在我也没玩明白这玩意,就算是rust圣经也说“虽然 Rust 中的宏很强大,但是它并不应该成为我们的常规武器”,但是我知道一点,它可以玩出许多有趣的奇淫技巧来。
回到安全机制上来,我们思考一个问题,C/C++能否在编译时像rust一样检测安全问题?rust又是否能像C/C++那样灵活地操作内存?答案当然是毋庸置疑的可以(safe C++,zig,unsafe rust,内联汇编等等),只不过当它们往反方向走时,书写会变得复杂很多。在这篇简短的文章中,作者也进行了深度的思考,结论是,尽管rust有一个新颖的伟大想法来实现高效的内存安全,但我们还是最求务实地坚持使用成熟的供应商HAL和C/C++工具链。我也有着类似的想法,原因十分的单纯,写习惯C/C++或者传统语言的自己实在是难以适应rust的变量使用机制,另一方面是尽管rust在高速成长,但论生态的话,想要和C/C++比的话,还是有较大差距的。还值得说的一点是,变量类型后置也挺不习惯的,虽然在现代的众多语言中变量后置十分常见,比如go和Kotlin两个典型代表,就算是我最爱的数学的形式语言也是如此,就算我知道其有直观表现复杂函数的能力……但是我还是改不了,因为我的主力语言不是这样的,这是没办法的。烦人的流程,我一直,尽管过了很久,我也不能明白在类中使用setter和getter的好处,管它什么封装安全什么的,我觉得最大的好处无非只是其中加了点函数性,干脆像C#那样搞个属性(Property)算了。虽然偏题了,我想说的就是,我讨厌麻烦,我喜欢自由灵活,我喜欢哪种操纵内存的感觉。正所谓,随机应变,需要什么语言,我们就用什么语言,有趣的东西,比如rust,学学也就够了,至于以后是否因为不用而忘记就是以后的事,因为学习一门编程语言的成本很低,付出最大的时间代价就是实践与磨合的过程。
我最早搞开发的时候,是在手机上用AIDE搞安卓应用开发的时候,当时安卓的主流开发语言还是java……嗯,最早搞开发的时候,或许是手机Minecraft还没进入1.0,还可以使用启动器使用js作为脚本语言进行Minecraft扩展的时候……算了,什么样都无所谓啦,反正都是java开头的。当然这也是无所谓的,当时的aide还有一个更强的利器,就是ndk,也正因如此,我第一次接触到了混合编程。什么是混合编程,从表面上看就是用多种编程语言写同一个程序,但要实现混合编程是有一定条件的,不同编程语言写在同一个文件中进行编译是几乎不可能的事情,除非其本身就存在包含关系,典型代表是C-C++-asm。更多情形的混合编程,主要是两种情况,一种是共同的目标代码,比如面向操作系统的汇编,因此在静态编译语言几乎都可以互相调用导出库,当然这样的目标语言也可以重构一份,clr的IL和java虚拟机就是经典代表,另一种则是生成关系,例如lua用C写成,所以它们可以互相调用,又例如在CPython中,C与Python也可以实现互调……更多的例子懒得说了,很多语言都可以实现自举,但毫无疑问的是,C/C++是众多语言之母,而且从操作系统层面上看,标准的C/C++实现基本是都有的。未来会如何,我并不清楚,但这些根深蒂固的东西不是一朝一夕可以改变的,就目前来看,不选择rust,而选择C/C++是我唯一能做好的事情。
有人可能会觉得混合编程不就是给自己徒增学习成本,而给自己增加麻烦用的吗?确实,混合编程大多数情况下,都只是给其他高级语言提高运行效率用的,利用原生的C/C++来实现汇编级别来实现系统级别的运行效率,其更多存在于生成关系中,而共同目标代码时一般确实也不会干这种无聊的事情。我在日常中还遇到过的一种情形是,C#作为上位机时使用由C/C++写成的系统驱动,其主要使用了一种称为P/Invoke的机制,其属于C#的一种机制,虽然看起来像是直接调用,但其只不过是减少了交互过程,本质上和各种生成关系式的交互没有太大的区别,你也可以理解成融合了一个swig在里面,或许有些无趣的区别,但我也不想,也没精力去研究了,计算机的世界太过于广阔了,放弃些不感兴趣的东西,也是情有可原的。混合编程在某种程度上其实挺常见的,关键在于你将什么视为一种语言,比如我有一个WPF项目,那么其首先至少包含三种语言,一是界面用的xaml,二是后台逻辑用的C#,三是配置用的xml,如果我需要底层驱动的话,又需要C/C++的支持,当我需要脚本扩展的时候,又会使用NeoLua进行lua脚本的扩展,如果我还需要展示网页的话,html/css/js又得引入吧,有时如果冒出一个远古项目依赖,偏偏又是vb写的,那总得把它加进来吧。好吧,还是说实话吧,说到底玩混合编程只是一时的三分热度而已,顺便提升一下对计算机运行的理解,玩多了是很容易玩脱的,而且还会被各种烦人的写法困扰,所以非迫不得已,还是少用混合编程。
虽然讲了很多无趣的东西,但我知道C/C++可以带我去往更广阔的天地,所以我选择了它。

10.10补:中招了,本来想研究一下体量稍微大一点的rust项目,于是试着cargo build(想加--release?没门)耍耍,结果…编译的时候卡得要死,编译过程好久,编译使用了快6、7G的磁盘空间,直接报空间不足而编译失败。…嗯…依我看,rust就还是先搞搞小项目,让它再沉淀个几年再说。