开始之前
安装Rust
环境,配置好VScode插件
。Win10系统可参考:Win10系统Rust安装
OK,接下来一起开始Rust之旅。Ready Go!
println!的基本使用、eprintln!、dbg!
Talk is cheap, show me the codes.
咱直奔主题。
找一个空目录,创建
m
a
i
n
.
r
s
main.rs
main.rs 文本文件,输入如下内容:
PS:本系列的精华内容在代码注释中,不要错过!
fn main() {
// println!是标准库中定义的宏规则,将格式化后的内容输出到stdout
// 宏的作用是告诉编译器,将相应的代码进行既定规则的替换(代码展开)
// rust的宏展开比C语言中的宏更强大,在进行代码替换的同时可以进行类型校验
// rust的宏展开是导致rust编译慢的一个重要原因
// 在编译器看来,宏展开不是函数调用,所以用小/中/大括号都可以接受
// 不过,为了让println!更像函数调用,建议用小括号
println!("hello world");
println!["hello world"];
println!{"hello world"};
let name = "Liberg";
let age = 20;
println!("I'm {}, {} years old.", name, age);
let v = 10;
// {}内部可以指定格式化参数的索引
println!("{0}*{0}={1}", v, v*v);
// 输出{},需要转义
println!("{{}}");
// 输出{100}
println!("{{{}}}", 100);
// 输出到stderr
eprintln!("some error happened");
let x = 100;
// 会打印出调试信息:文件名+行号+表达式的值
// [xxx.rs:30] x > 50 = true
dbg!(x > 50);
}
rustc编译、运行
D:\dev\rust\test_cli>rustc main.rs #rustc进行编译
D:\dev\rust\test_cli>main #运行编译出的可执行文件
hello world
hello world
hello world
I'm Liberg, 20 years old.
10*10=100
{}
{100}
some error happened
[main.rs:27] x > 50 = true
温馨提示:
- 如果还没有完成安装Rust语言环境,可以暂时将代码拷贝到Rust官方的Playground中在线运行,地址Rust Playground
- 学习Rust语言,需要安装Rust语言的开发运行环境。请读者自行搜索相关内容完成开发环境的配置。如果是Win10系统,可以参考笔者之前的安装过程:Win10系统Rust环境安装
{:p}格式打印引用的地址
let v = 10;
// p是v的借用(引用)
let p = &v;
// {:p}的格式可以打印引用本身在内存中的地址
println!("addr of v: {:p}", p);// addr of v: 0x96537ff104
// *p取得引用p所指向的值
println!("v = {}", *p);// v = 10
// &p是一个新的引用,这个引用指向的是栈内存中的p
println!("addr of &p: {:p}", &p);// addr of &p: 0x96537ff1e8
println!("v = {}", **(&p));// v = 10
// 引用占4个字节
println!("size of p: {}", std::mem::size_of_val(p));//size of p: 4
进阶之门
println!
支持丰富的格式化参数,笔者在【Rust编程小知识】栏目下整理了一份清单:
Rust格式化输出:println、format格式化参数详解
自定义宏:my_max! my_as!
模仿println!
,来自定义一个简单的宏规则my_max!
:求两个整数中的较大者。
fn main() {
// macro_rules!是定义宏规则的关键字
macro_rules! my_max {
// $x和$y用于指代要匹配的输入
// 紧接着冒号后面是输入的类型,常见的有:
// tt 匹配一个token
// ty 匹配一个类型,比如i32、Vec列表类型等
// expr 匹配一个表达式
// stmt 匹配一个语句,比如赋值语句、return语句。
// block 匹配一个代码块{...}
// item 匹配函数、结构体、模块等
($x:tt, $y:tt)=>{
if $x > $y {$x} else {$y}
}
}
println!("{}", my_max!(3,4));//4
//30usize表示usize类型的30
println!("{}", my_max!(30usize,40usize));//40
}
如果觉得还不过瘾,可以尝试一下将 10 as i16
这样的代码,通过抽取前面的数值和as后面的类型作为宏参数,包装一个宏出来。这个宏本身没啥用,仅作练习。
as关键字用作类型转换:
let x = 10;//默认x是i32类型
let y = 10 as u8;//y是u8类型
我们来尝试一下:
macro_rules! my_as {
($v:tt, $t:ty)=>{
$v as $t
}
}
//等价于: lex x = 10 as i16;
let x = my_as!(10, i16);
println!("x={}", x);//10
//因为是i16类型,所以占用2个字节
println!("size of x={}", std::mem::size_of_val(&x));
当然,这只是最简单的一类宏。Rust中宏的强大可能完全超出你的想象。关于宏的更多内容后面会单独介绍。期待再见!
参考文档:https://doc.rust-lang.org/rust-by-example/macros.html