Hello, world!
现在,你已经安装了Rust,让我们开始写第一个Rust程序。 在学习新语言的时候,有一个传统,就是写一个小程序来打印“hello,world!”,在本节,我们将遵循这一传统。
以这样一个简单程序开始的一个好处就是,你可以快速验证编译器是安装好并能正常工作的。 在屏幕上打印信息也是很常见的,所以尽早练习也是件好事。
注: 本书假设读者已熟悉命令行。 Rust本身并没有具体要求你使用哪种工具、编辑器,所以如果你喜欢用IDE,那也是可以的。
创建项目文件
首先,创建一个文件来写Rust代码。Rust并不关心你的代码在哪,但是对于本书来说, 我的建议是在你的home目录下创建一个 projects 目录,并且把所有的项目都放在里面。 打开终端并且输入下列命令来为这个特别的项目来创建一个目录:
$ mkdir ~/projects
$ cd ~/projects
$ mkdir hello_world
$ cd hello_world
注:如果你是在Windows下,并且没有使用PowerShell,那么
~
将不会工作。 请自行翻阅关于shell更详细的文档。
写一个Rust程序并运行
接下来,创建一个新的源文件,命名为 main.rs 。Rust文件总是以 .rs 扩展名结尾。 如果你的文件名需要以多个单词命名,那么你最好用下划线来分隔这两个单词, 比如,使用 hello_world.rs 来代替 helloworld.rs。
现在,打开你刚刚创建好的 main.rs 文件,并且输入下面代码:
fn main() {
println!("Hello, world!");
}
保存这个文件,并且返回到终端窗口。在Linux或Mac下,可以输入下面命令:
$ rustc main.rs
$ ./main
Hello, world!
对于Windows来说,只需要把main
换成main.exe
。
不管你用哪种操作系统,你应该会看见终端输出Hello,world!字符串。
如果你完成了上述示例,那么恭喜你!
你已经正式写了一个Rust程序,你已经成为一名Rust程序员了!欢迎。
Rust程序剖析
现在,让我们来了解一下刚才“Hello,world!”程序的细节。下面是第一部分:
fn main() {
}
该行代码定义了一个Rust函数。main函数比较特殊:它是每个Rust程序的起点。
第一行的意思是,“我定义来一个名为main的函数,没有参数,也没有返回任何值”。
如果这里有参数,那参数将会放在括号((
和 )
)内,并且因为我们没有从该函数中返回任何值,
我们可以完全忽略返回类型。
也要注意,该函数体是被包裹在大括号 ({
和 }
)中的。
Rust要求所有的函数体都必须如此,一个比较好的风格,就是把大括号跟函数声明放在同一行,两者之间隔一个空格。
在main()
函数内部:
println!("Hello, world!");
该行代码在这个小程序中的作用就是: 在屏幕上打印文本。 这里有许多重要的细节,首先,这里(println前面)有四个空格,而非制表符。
第二个重要的部分就是println!()
这行。它实际上是调用了一个 Rust宏(macro) ,宏是用来实现Rust元编程的。如果直接调用函数而不是宏,则可以写成这样:println()
(注意,这里没有”!”)。
我们将在之后讨论Rust宏的更多细节,但是现在你只需要知道,当你看到“叹号(!)”的时候,意味着你调用的是宏,
而非普通函数。
接下来是“Hello,World!”这个 字符串 。
我们把该字符串传作为参数传给println!
,此宏负责把字符串打印到屏幕上。就是这么简单!
整行代码以分号(;
)结尾。Rust是一个 表达式导向(expression oriented ) 的语言,即Rust里大部分东西都是表达式(expression),而非语句(statement)。
;
表示这个表达式已经结束,并且下一个准备开始。Rust代码中大多数都是以分号(;
)结尾。
编译和运行是独立的两步
在“写一个Rust程序并运行”小节,我们展示了如何运行一个新创建的程序。我们现在将打破这个过程,来研究每一个步骤。
在运行Rust程序之前,你必须编译它。你能通过输入rustc命令来使用Rust编译器,给它传入一个源文件名即可,像这样:
$ rustc main.rs
如果你有C或C++背景,你会注意到这和gcc
或clang
很相似。
在编译成功以后,Rust应该会输出一个二进制可执行文件,在Linux或Mac上,你可以通过ls命令来查看,如下所示:
$ ls
main main.rs
在Windows上,你输入:
$ dir
main.exe main.rs
这些命令会显示两个文件:使用.rs
扩展名的源码文件和可执行文件(Windows上是main.exe
,其他是main
)。
剩下的事情就是运行mian
或main.exe
文件了,像这样:
$ ./main # or main.exe on Windows
如果 main.rs 是你的“Hello,World!”程序,它将会在你的终端打印“Hello,World!”。
如果你有动态语言的背景,比如用Ruby、Python或JavaScript这些语言,你可能不需要把编译和运行分成独立的两步去做。 Rust是 预编译 语言,也就是说,只要你编译了这个程序,然后把它随便给一个人,他都可以直接运行该程序而不需要安装Rust。 如果你给一个人.rb或.py或.js文件,他们需要分别安装Ruby、Python和JavaScript,但是只需要一个命令就能完成编译和运行该程序。 一切都在于语言设计的权衡。
对于简单的程序来说,只需要用rustc编译就好了,但是当你的项目的增长,你会希望能够管理你项目中所有的选项, 并且可以把它容易的共享给其他人和项目。接下来,我将介绍一个叫做Cargo的工具,它用来帮助我们去写真实世界的Rust程序。
Hello, Cargo!
Cargo是Rust的构建(build)系统和包管理器,Rustacean们用Cargo去管理他们的Rust项目。 Fargo管理三件事:构建你的代码、下载你代码依赖的库,以及构建这些库。 我们调用你代码需要“依赖(dependencies)”的库,因为你的代码依赖于它们。
最简单的Rsut程序没有任何依赖,所以现在,你只使用了其功能的第一部分。 当你编写更复杂的Rust程序的时候,你就会添加依赖,如果你使用了Cargo,这一切将会更容易去做。
绝大多数的Rust项目都用Cargo,我们将在本书余下的部分都使用它。如果你用了官方的安装程序, Cargo是连同Rust一起被安装的。如果你通过其他途径安装Rust,你可以通过在终端输入下面命令来检查Cargo是否被安装:
$ cargo --version
如果你能看到版本号,那是极好的!如果你看到了像“command not found
”这样的错误,
那么你应该看看你安装Rust的那个文档,确定下Cargo是不是分开安装的。
开始使用Cargo
让我们把那个Hello World程序换成Cargo的。想Cargo化一个项目,你需要做三件事:
- 把你的源文件放到正确的目录下。
- 摆脱旧的可执行文件(Windows上的main.exe,其他是main),并且生成一个新的。
- 创建一个Cargo配置文件。
让我们开始吧!
创建一个新的可执行文件和源目录
首先,打开你的终端,进入hello_world目录,然后输入下面命令:
$ mkdir src
$ mv main.rs src/main.rs
$ rm main # or 'del main.exe' on Windows
Cargo期望你的源文件待在 src 目录里,所以你先得完成这一步。 留在顶级项目目录(在本例中是 hello_world 根目录)中的文件是READMEs、license信息和其他完全和代码无关的文件。 这样一来,使用Cargo可以帮助你保持项目的美丽和整洁。 人神各有层天,各归其位!(There's a place for everything, and everything is in its place.)。
现在,把 main.rs 文件复制到 src 目录中,并且删除你用rustc创建的已编译文件。
跟之前一样,如果你用了Windows,那么就是删除main.exe
,其他操作系统是main
。
该示例保留了main.rs
做为源文件名,因为它创建了可执行文件。
如果你想生成一个库,你需要把文件命名为lib.rs
。
Cargo使用这个约定来使编译成功,但是如果你愿意的话也可以重写约定。
创建配置文件
接下来,在你的 hello_world 目录中创建一个新的文件,命名为Cargo.toml。
确保Cargo.tom文件名的首字母C是大写,否则Cargo将忽略掉配置文件。
该文件是 TOML(Tom’s Obvious,Minimal Language,译者本身也翻译了TOML的文档,但是pull request一直没被merge,感兴趣的可以去看)格式的。TOML类似于INI,但是有一些其他优点,它被用来作为Cargo的配置文件格式。
在该文件中,输入以下信息:
[package]
name = "hello_world"
version = "0.0.1"
authors = [ "Your name <you@example.com>" ]
第一行,[package]
,表明下面的语句是配置一个包。
当我们在该文件中添加更多信息的时候,我们将添加其他片段,但是现在,我们只有包配置信息片段。
剩下的三行设置了Cargo编译程序时候需要的三部分配置信息:它的名字、它的版本号和它的作者。
一旦你将这些信息添加到 Cargo.toml 文件中并保存之后,那么配置文件也就创建完成了。
构建并运行一个Cargo项目
通过项目根目录下的 Cargo.toml 文件,你应该可以构建并运行你的Hello World程序了!输入下列命令来完成它:
$ cargo build
Compiling hello_world v0.0.1 (file:///home/yourname/projects/hello_world)
$ ./target/debug/hello_world
Hello, world!
如果一切顺利,你将在终端再次看到Hello,world!
你刚才是用cargo build
构建了一个项目,并且使用了./target/debug/hello_world
运行了它,
但是你实际上可以使用cargo run
命令一步完成那两个动作,如下所示:
$ cargo run
Running `target/debug/hello_world`
Hello, world!
注意,这个例子并不是重新构建此项目。Cargo发现该文件并没有被改变,所以它只是运行了二进制可执行文件。 如果你修改了你的源代码,Cargo会重写构建项目再运行,你可以会看到类似这样的输出:
$ cargo run
Compiling hello_world v0.0.1 (file:///home/yourname/projects/hello_world)
Running `target/debug/hello_world`
Hello, world!
Cargo知道你项目文件中任何修改,如果最新一次build之后文件有所改变,那么Cargo将会重新构建项目。
对于简单项目来说,Cargo并没有使用到它的诸多功能而只是用了rustc
,但是它在以后会非常有用。
对于复杂的项目,用Cargo来协调构建过程会使一切变得更简单。
用Cargo,你可以只运行cargo build
,也是它的正确工作方式。
构建发行版
当你的项目最终做好了发行的准备,你可以用cargo build —release
命令来优化编译你的项目。
这些优化会使你的Rust代码运行的更快,但是换来的代价是你的程序会编译的更慢。
这就是为什么有两个不同的配置文件,一个是为了开发,另一个用于构建你分发给用户的最终版本。
运行该命令也会让Cargo创建一个新的文件,叫 Cargo.lock,看起来像这样:
[root]
name = "hello_world"
version = "0.0.1"
Cargo使用 Cargo.lock 文件来记录你应用中的依赖。 这是Hello World项目中的 Cargo.lock 文件。 该项目没有任何依赖,所以该文件有点单薄。实际上,你永远不需要亲自接触这个文件,只需要交给Cargo处理就行了。
如果你是从头到尾跟着做的话,你现在应该已经成功使用Cargo构建了hello_world。
尽管该项目很简单,但是它多少也是使用了你以后Rust职业生涯中会用到的真正工具。事实上,你可以认为实际上所有的Rust项目都是使用下面命令的变种:
$ git clone someurl.com/foo
$ cd foo
$ cargo build
创建新的Cargo项目最简单的方式
这是你每次开始一个新项目之前必须要做的过程。Cargo可以快速的生成一个基础项目目录,让你能保持正确的开发姿势。
用Cargo创建新的项目,只需要键入cargo new
命令:
$ cargo new hello_world --bin
该命令传入--bin
,是因为我们的目的是直接获取可执行的应用程序,而非一个库。
可执行文件通常被叫做 二进制文件(如果你用了Unix系统,这类文件在/usr/bin目录中)。
Cargo为我们生成了两个文件和一个目录:Cargo.toml 和 src 目录,以及 src 中的 main.rs 文件。 这应该很熟悉了吧,我们在上面的内容中手工创建过。
这便是你开始项目所需要的东西。首先,打开 Cargo.toml。应该能看到跟下面类似的内容:
[package]
name = "hello_world"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
Cargo已经根据你给的参数和你的git
全局配置自动填充了合适的内容。
你可能也注意到了,Cargo已经把hello_world
目录初始化为了git
仓库。
在src/main.rs
中应该能看到如下内容:
fn main() {
println!("Hello, world!");
}
Cargo已经为你生成了“hello world!”,你就可以开始coding了!
注:如果你想了解Cargo更详细的内容,可以去翻阅官方的Cargo guide,那里覆盖了它所有的特性。