讲动人的故事,写懂人的代码
- 故事梗概:
- 在她所维护的老旧Java系统即将被淘汰的危机边缘,这位在编程中总想快速完事的女程序员,希望能转岗到公司内部使用Rust语言的新项目组,因此开始自学Rust;
- 然而,在掌握了Rust编程知识之后,为了通过Rust项目组的技术面试,使得转岗成功而不至被裁员,她必须领会编程如何"快速"才能有真正的意义。
上回的故事里,我们的Java程序员赵可菲和C 程序员席双嘉,在Rust大神贾克强的指导下,一起掌握了rustup工具链的用法。
接下来,他们准备把Rust书里的Guessing Game的需求稍作修改,然后重新写一遍代码,这样就能更好地学习Rust的基础知识了。
2.1 猜骰子冷热游戏需求
那么,该如何调整书中的Guessing Game游戏的需求,让它既好玩又可以让大家练习书中的知识点呢?
贾克强突然想起了公司新近部署的AI编程助手艾极思。他想,也许可以问问它。
于是,贾克强对艾极思说:“我希望你能根据下面《The Rust Programming Language》书中的游戏描述,帮我改编一下需求,设计一个新游戏。新游戏要趣味十足,而且要保留原游戏的关键行为,让我在重写代码的过程中,可以练习到书中的主要知识点。”
“书中原游戏的描述是这样的:这是个猜数字的游戏,首先,程序会生成一个1到100之间的随机整数。“
”然后,程序会提示玩家猜这个数。“
”玩家输入他们所猜的数字后,程序会告诉他们这个猜测是偏低还是偏高。如果猜对了,游戏就会打印一条祝贺信息然后结束。”
艾极思马上回复了:“根据《The Rust Programming Language》书中的原游戏,我们可以设计一个新游戏,既保留了原有的基本逻辑,也加入了一些有趣的元素和挑战。“
”这样你在练习编程的同时,也可以享受游戏的乐趣。以下是新游戏的设定:”
“新游戏叫做:猜骰子冷热(Dicey Temperatures)”
“游戏规则是这样的:”
“1 首先,程序会生成两个骰子的点数之和,这个数是2到12之间的随机整数。”
“2 然后,程序会提示玩家猜两个骰子的点数之和。”
“3 如果玩家第一次输入点数之和就答错了,程序就会提示‘第一次猜就错了哦’。”
“4 如果玩家第二次或之后输入点数之和也答错了,但这次猜测比上次更接近正确答案,程序就会提示‘更热了’。”
“5 如果离正确答案更远了,程序就会提示‘更冷了’。”
“6 如果距离正确答案的距离和上次一样,程序就会提示‘不冷不热’。”
“7 如果玩家猜对了,程序就会提示‘恭喜你,猜对了!’”
大家看到艾极思的回复,都觉得这个新游戏真的很好玩。
接下来,就可以开始新的项目了。
2.2 如何创建一个Rust新项目
赵可菲:“创建新项目真是小菜一碟。书里写的超详细的,直接运行cargo new diceytemperatures
就搞定了。”
2.3 Rust语言的命名风格
贾克强指着赵可菲的屏幕说:“等等。项目名要用锈族的snake_case风格哈。”
“其实嘛,Rust在英文里就是铁锈的意思,所以我们国内的朋友们就直接叫Rust程序员为锈族啦。“
”而且你知道吗,国外的Rust程序员他们自己都爱叫自己甲壳族(Rustaceans),因为这个词跟甲壳生物Crustacean差不多嘛。“
”有一些外国的程序员朋友就把那个橙色的螃蟹Ferris当做Rust程序员的非官方吉祥物了(如图2.1)。“
"锈族或者甲壳族,对于所有的变量名、方法名、函数名、项目名、包名和模块名,我们都喜欢用snake_case风格哟。只有类名,我们才会用PascalCase。"
"snake_case风格,很简单明了,就是所有的单词都是小写,用下划线连接起来。”
赵可菲:“哦,我可能需要一点时间来适应这个锈族的习惯。”
她一边说,一边把命令改成cargo new dicey_temperatures
。
zkf@mbp ~ cargo new dicey_temperatures
Created binary (application) `dicey_temperatures` package
“在Java的世界里,给项目起名字,真没有什么硬性规定。”
席双嘉:“C 这边也是如此,没有定论。”
席双嘉告诉赵可菲:“咱们搞定新项目后,就用git提交一次,怎么样?每改一点点就提交一次,这样就能明显看出哪些文件变了。”
赵可菲回应:“这主意不错。不过,我可没那么有耐心。这个提交的事你来吧。”
“没问题。“席双嘉接过键盘,顺手就用git提交了代码。
赵可菲接着又输入了cargo run
来启动程序,屏幕上出现了“Hello, world!”。
2.4 确保构建稳定可靠的Cargo.lock文件
“看!”席双嘉一边指着屏幕一边说,“终端窗口提示符的颜色,从绿变黄了。这就意味着代码在上次提交后有点变化。”
赵可菲:“但是我们只是运行了程序,代码应该没动呀。”
席双嘉敲了下git status -uall
,这样就能显示出所有未被git跟踪的文件。
屏幕上出现了一个名叫Cargo.lock的文件。
代码语言:javascript复制 zkf@mbp ~/dicey_temperatures ↱ main git status -uall
On branch main
Your branch is ahead of 'origin/main' by 1 commit.
(use "git push" to publish your local commits)
Untracked files:
(use "git add <file>..." to include in what will be committed)
Cargo.lock
nothing added to commit but untracked files present (use "git add" to track)
席双嘉:“看,只要一运行cargo run
,Cargo.lock文件就被自动创建出来了嘛。”
他随便点开了这个文件。
代码语言:javascript复制# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "dicey_temperatures"
version = "0.1.0"
赵可菲:“嘿,这个文件需要提交到版本库吗?”
贾克强:“对的,Cargo.lock文件得提交到版本库,让我们的构建更稳定和可靠。”
“就像咱们程序员最怕的那种情况,明明在自己这儿代码运行得好好的,但怎么在测试环境就犯傻了。”
“许多时候,这就是因为开发环境和测试环境不一致。”
“也就是说,虽然构建的是同一份代码,但由于环境差异,开发环境能跑的包在测试环境再构建后就跑不通了。这两个包本身就不一样。”
“Cargo.lock文件就是为了解决这个问题。”
“当你运行 cargo build
时,Cargo 会查看一下 Cargo.toml
文件,看看哪个版本的依赖项最合适。”
“然后它会把这些版本写入 Cargo.lock
文件。一旦有了这个文件,Cargo 会忽略所有的更新,只参考这个文件。”
“除非你想更新。那就得用 cargo update
。”
“这个机制就保证了我们构建的包,无论过多久或是谁去构建,都是一致的,保护我们的项目不被新版本的依赖项带来的问题影响。”
赵可菲:“但我们并没有运行cargo build
命令呀。”
贾克强:“哈哈!你们刚才运行的cargo run
命令呀。“
”它会先执行cargo build
来编译你的项目。如果编译成功,cargo run
接着就会运行编译后的二进制文件。”
贾克强话音未落,席双嘉已经把Cargo.lock文件提交到版本库了。
2.4.1 Java世界如何确保构建稳定可靠
赵可菲笑着说:“在Java的世界里,要实现类似Rust中Cargo.lock
的功能,我们得靠Maven和Gradle这两大神器了。”
“Maven就是通过pom.xml
文件来管理项目的依赖。“
”要锁定依赖版本,保证我们构建的东西能稳稳的运行,Maven通常会在<dependencyManagement>
里头指定依赖的具体版本,或者用Maven Enforcer插件之类的外部工具。“
”虽然Maven没有直接类似于Cargo.lock
的文件,但我们可以在pom.xml
中明确所有版本,并利用<dependencyManagement>
来锁定它们。”
“此外,Maven的发行版和快照机制,也能分别帮我们管理稳定构建和开发构建。”
“然后是Gradle,它通过build.gradle
文件来配置依赖。”
“和Maven一样,Gradle原来并不会自动产生锁文件,不过我们可以通过依赖约束等策略来达到类似的效果。”
“从Gradle 4.8版本开始,它引入了依赖锁文件的概念,允许我们开发者明确锁定版本。”
“只要运行gradle dependencies --write-locks
命令,Gradle就会生成一个锁文件,这个文件会固定依赖的版本,这在功能上就像Rust的Cargo.lock
一样,保证了不同环境和时间下构建结果的一致性。”
2.4.2 C 世界如何确保构建稳定可靠
席双嘉:“嗨,你知道吗?在C 的世界里,我们也有类似Rust中的Cargo.lock机制,就是用Conan这个小工具。”
“Conan,这可是专门为C 量身打造的包管理器哦,它能帮我们处理所有的依赖和版本控制问题,让项目构建得稳稳当当。”
“用Conan的话,它会给我们生成一个叫做conan.lock
的文件,这个玩意儿和Rust的Cargo.lock
差不多。”
“这个conan.lock
文件的作用就是把项目依赖的版本给锁定住,这样无论在哪个环境下构建,依赖都能保持一致。”
“这样一来,就能避免因为依赖版本不同,在开发、测试和生产环境中出现的那些麻烦事儿。”
“虽然CMake本身并没有内建的生成锁文件的功能,但它可以跟Conan这样的包管理器搭个档,通过Conan来管理依赖和版本,也就能间接实现锁定机制了。”
“在CMake的项目里,你可以在CMakeLists.txt
文件中包含Conan的配置,然后通过链接Conan管理的库来构建应用程序。”
2.5 小结
两位程序员在Rust大神的带领下,决定给原有的Rust编程书籍中的"Guessing Game"游戏需求来点变化,重新操刀代码。
他们找了个AI编程小助手艾极思,把游戏需求改头换面,变成了一个新的、好玩儿的游戏“猜骰子冷热”。
这个新游戏不仅保留了原游戏的精髓,还加入了新的元素和挑战,让编程学习变得更加有趣。
他们用 cargo new
命令创了个新的Rust项目,还学习了Rust语言的命名风格。
命名风格 | Rust/Python | Java/Kotlin/Scala | C/C |
---|---|---|---|
Class Name | PascalCase | PascalCase | PascalCase |
Method Name | snake_case | camelCase | camelCase |
Variable Name | snake_case | camelCase | snake_case |
Function Name | snake_case | - | snake_case |
Project Name | snake_case | - | - |
Package Name | snake_case | lowercase | - |
Module Name | snake_case | - | - |
项目搞定后,他们咔嚓一下cargo run
,程序就跑起来了。你会发现,跑这个命令会自动弄出个Cargo.lock
文件。
这小文件可是厉害了,它能保证我们构建的稳定性和一致性呢。Java和C 的世界里,也有类似的东西,比如Java的Maven和Gradle,C 的Conan等等。
语言 | 机制 | 文件 | 特性 |
---|---|---|---|
Rust | Cargo | Cargo.lock | 锁定依赖版本。通过cargo build或cargo run自动创建和更新。 |
Java | Maven/Gradle | pom.xml/build.gradle | 通过Maven的<dependencyManagement>和Gradle的依赖约束来锁定依赖版本。Gradle 4.8 可以生成一个锁文件。 |
C | Conan | conan.lock | 锁定依赖版本。与CMake一起管理依赖和版本。 |
如果你想要了解Rust是如何通过超越传统赋值语句的binding,实现不变性、模式匹配和所有权设计理念的,那就关注我,继续看下去吧!
【未完待续】
如果喜欢我的文章,期待你的点赞、在看和转发。
如果不喜欢,在评论区留个言告诉我哪里不喜欢呗~