rust02语法

 

单引号和双引号

错误的写法
fn main() {
    println!('hello world');
}


# 错误信息
error: character literal may only contain one codepoint: ')
 --> src/main.rs:2:26
  |
2 |     println!('hello world')
                             ^^
正确的写法
fn main() {
    println!("hello world");
}
小结

变量定义全部采用双引号, 不能采用单引号。

 

行结束符 ;

错误的写法
fn main() {
    println!("hello world")
    println!("sssssssssss")
}


# 错误信息
error: expected one of `.`, `;`, `?`, `}`, or an operator, found `println`
 --> src/main.rs:3:5
  |
2 |     println!("hello world")
  |                            - expected one of `.`, `;`, `?`, `}`, or an operator here
正确的写法
fn main() {
    println!("hello world");
    println!("sssssssssss");
}
小结

每行执行代码后面最好带上一个行结束符;

 

缩进

无缩进(支持)
fn main() {
println!("hello world"); 
}
空格缩进(支持)
fn main() {
    println!("hello world");
}

tab缩进(支持)
fn main() {
        println!("hello world");
}
小结

rust 对缩进没有要求, 但是鼓励采用4个空格来对代码块进行缩进.

 

main特殊函数

直接将代码暴露在全局作用域中, 也就是说不写main.
println!("hello world");


# 报错信息
error: macros that expand to items must either be surrounded with braces or followed by a semicolon
 --> <println macros>:2:9
  |
2 | print ! ( concat ! ( $ fmt , "\n" ) ) ) ; ( $ fmt : expr , $ ( $ arg : tt ) *
  |         ^^^^^^^^^^^^^^^^^^^
将代码封装在函数中, 不写main.
fn simple() {
    println!("hello world");
}


# 报错信息
error: main function not found
正确的写法
fn simple() {
    println!("hello world");
}

fn main() {
    simple();
}
main函数不能定义参数
fn main(first: i32, second: f64) {     // 不能定义参数
    println!("{} {}", first, second)
}
main函数不能定义返回值
fn main() -> String {                   // 不能定义返回值
    let s = String::from("hello");
    s
}
普通函数使用return返回值
fn simple_function() -> i32 {
    let s = 10;
    return s
}

fn main() {
    let s = simple_function();
    println!("{}", s)
}
普通函数不用return返回值(官方推荐、源码规范)
fn simple_function() -> i32 {
    let s = 10;
    s
}

fn main() {
    let s = simple_function();
    println!("{}", s)
}
小结
  1. 在全局作用域中不能直接撰写执行类型的语句。
  2. main特殊函数, 是所有程序的入口, 所以封装好所有代码之后, 必须放入到main中被rust识别和运行。

 

变量

变量不能定义在函数外
let s = "a";

fn main() {
    println!("hello world! {}", s)
}


# 报错信息
error: expected item, found `let`
 --> main.rs:1:1
  |
1 | let s = "a";
  | ^^^
  


# 正确的写法
fn main() {
    let s = "a";   // 变量定义写在函数内
    println!("hello world! {}", s);
}
变量不能直接被打印
fn main() {
    let s = "a";
    println!(s);
}

# 报错信息
error: expected a literal
 --> main.rs:3:14
  |
3 |     println!(s);
  |              ^
  
  
  
# 正确的写法
fn main() {
    let s = "a";
    let x = "xxx";
    println!("{} {}", s, x);
}
变量默认不能被修改
fn main() {
    let s = 1;
    s += 2;
    println!("{}", s)
}

# 报错信息
error[E0384]: re-assignment of immutable variable `s`
 --> main.rs:3:5
  |
2 |     let s = 1;
  |         - first assignment to `s`
3 |     s += 2;
  |     ^^^^^^ re-assignment of immutable variable



# 正确的写法
fn main() {
    let mut s = 1;
    s += 2;
    println!("{}", s);
}
可更改变量必须类型相同
fn main() {
    let mut s = 10;
    s += 'abc';
}

# 报错
error: character literal may only contain one codepoint: 'abc'
  --> main.rs:25:10
   |
25 |     s += 'abc';
   |          ^^^^^

error: aborting due to previous error(s)

变量遮盖(Shadowing)
fn main() {
    let s = 1;
    let s = 2 + 10;
    println!("{}", s);
}


# 编译时报警告, 运行时正常; 编译器认为这种写法并不符合规范
# 但也是可以运行的, 因为第一个`let s = 1`没有被使用就被
# 覆盖掉了, 这种情况完全可以不用定义这行代码.
   Compiling datatype v0.1.0 (file:///opt/learn_rust/datatype)
warning: unused variable: `s`
 --> src/main.rs:2:9
  |
2 |     let s = 1;
  |         ^
  |
  = note: #[warn(unused_variables)] on by default

    Finished dev [unoptimized + debuginfo] target(s) in 0.46 secs
     Running `target/debug/datatype`
12



# 正确的Shadowing写法
fn main() {
    let s = 1;
    let s = s + 10;
    println!("{}", s);
}

 
 

变量赋值

整数类型变量
fn main() {
    // "i32"   
    // 公式: -(2 ** (32 - 1))  ~  (2 ** (32 - 1)) -1
    // 结果: -2147483648     ~   2147483647
    let s = 150;          
    println!("{}", s);    
}


fn main() {
    // "u32"   
    // 公式: 0 ~ (2 ** (32 - 1)) -1
    // 结果: 0 ~  4294967295
    let s: u32 = 4294967295;          
    println!("{}", s);    
}
浮点类型变量
fn main() {
    let s = 3.14;       // "f64"
    println!("{}", s);
}
字符串变量
fn main() {
    let s = "hello";      // "&str"
    println!("{}", s);
}
数组数字变量
fn main() {
    let s = [1, 2, 3, 4];   // "[i32; 4]"
    println!("{}", s);
}



# 编译时报错,
   Compiling datatype v0.1.0 (file:///opt/learn_rust/datatype)
error[E0277]: the trait bound `[{integer}; 4]: std::fmt::Display` is not satisfied
 --> src/main.rs:3:20
  |
3 |     println!("{}", s);
  |                    ^ the trait `std::fmt::Display` is not implemented for `[{integer}; 4]`
  |
  = note: `[{integer}; 4]` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string
  = note: required by `std::fmt::Display::fmt`

error: aborting due to previous error

error: Could not compile `datatype`.

To learn more, run the command again with --verbose.



# 正确的写法
fn main() {
    let s = [1, 2, 3, 4];     // "[i32; 4]"
    println!("{:?}", s);
}
数组字符串变量
fn main() {
    let s = ["a", "b", "c"];     // "[&str; 3]"
    println!("{:?}", s);
}
数组混搭元素
# 数组中的变量只能是相同类型的, 下面这个例子会报错, 详细的介绍请参考这里:
# https://rustbyexample.com/primitives/array.html  

fn main() {
    let s = ["a", 1, 2, "b"];     
    println!("{:?}", s);
}

error[E0308]: mismatched types
  --> main.rs:12:19
   |
12 |     let s = ["a", 1, 2, "b"];
   |                   ^ expected &str, found integral variable
   |
   = note: expected type `&str`
              found type `{integer}`

error: aborting due to previous error(s)




# 数组中的变量只能是相同类型, 并且元素内的结构也要保持一直.
# 错误的写法
fn main() {
    let s = [
        ["a", "b", "c", "d"],
        ["e", "f", "g", "h", "i"],
    ];   
    println!("{:?}", s);
}

# 正确的写法
fn main() {
    let s = [                               // "[[&str; 4]; 6]"
        ["a", "b", "c", "d"],
        ["e", "f", "g", "h"],
        ["i", "j", "k", "l"],
        ["m", "n", "o", "p"],
        ["q", "r", "s", "t"],
        ["q", "r", "s", "t"],
    ];  
    println!("{:?}", s);
}

# 正确的写法
fn main() {
    let s = [                               // "[(&str, i32); 6]"
        ("a", 1), ("b", 2), ("c", 3),
        ("d", 4), ("e", 5), ("f", 6),
    ];   
    println!("{:?}", s);
}
元祖数字变量
fn main() {
    let s = (1, 2, 3, 4, 5);                // "(i32, i32, i32, i32, i32)"
    println!("{:?}", s);
}
元祖字符串变量
fn main() {
    let s = ("a", "b", "c");                // "(&str, &str, &str)"
    println!("{:?}", s);
}
元祖混搭变量
fn main() {
    let s = (                               
        "a", 1, 2, "b",                     // "(&str, i32, i32, &str, 
        [3, 4], ["c", "d"],                 //   [i32; 2], [&str; 2], 
        [[4, 5], [6, 7]],                   //   [[i32; 2]; 2], 
        [["e", "f"], ["g", "h"]]            //   [[&str; 2]; 2])"
    );
    println!("{:?}", s);
}

 

我是如何打印这些变量类型的?
// 使用rust-nightly版本.
// 代码参考: https://users.rust-lang.org/t/get-the-type-of-a-var/3618/2

#![feature(core_intrinsics)]

use std::intrinsics::type_name;

fn test_type<T>(_: T) {
    println!("{:?}", unsafe { type_name::<T>() });
}

fn main() {
    let s = (
        "a", 1, 2, "b",
        [3, 4], ["c", "d"],
        [[4, 5], [6, 7]],
        [["e", "f"], ["g", "h"]]
    );
    test_type(s);
}

 
 

常量

字符串常量
const program_language: &'static str = "Rust";

fn main() {
    let hello = "Hello";
    println!("{} {}!", hello, program_language);
}


# 编译时报警告, 运行时正常;
# 编译器认为常量的变量名应该是由大写字母构成的;
   Compiling datatype v0.1.0 (file:///opt/learn_rust/datatype)
warning: constant `program_language` should have an upper case name such as `PROGRAM_LANGUAGE`
 --> src/main.rs:1:1
  |
1 | const program_language: &'static str = "Rust";
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: #[warn(non_upper_case_globals)] on by default

    Finished dev [unoptimized + debuginfo] target(s) in 0.43 secs
     Running `target/debug/datatype`
Hello Rust!



# 正确的写法
const PROGRAM_LANGUAGE: &'static str = "Rust";

fn main() {
    let hello = "Hello";
    println!("{} {}!", hello, PROGRAM_LANGUAGE);
}
浮点常量
const PROGRAM_VERSION: f64 = 1.18;
const PROGRAM_LANGUAGE: &'static str = "Rust";

fn main() {
    let hello = "Hello";
    println!("{} {}: {}!", hello, PROGRAM_LANGUAGE, PROGRAM_VERSION);
}
整数常量
# 数字可以用下划线来标识, 不影响实际的数字数值, 便于阅读.
const NUMBER: i32 = 100_000_000;

fn main() {
    println!("{}", NUMBER);     // 输出: 100000000 
}


# 有符号整数: "i32"     i == sign == 有符号整数(-表示负数)
# 公式: -(2 ** (32 - 1))  ~  (2 ** (32 - 1)) -1
# 结果: -2147483648     ~   2147483647
const ROLLBACK_VERSION: i32 = 2;  
const PROGRAM_LANGUAGE: &'static str = "Rust";

fn main() {
    let hello = "Hello";
    println!("{} {}: {}!", hello, PROGRAM_LANGUAGE, ROLLBACK_VERSION);
}




# 无符号整数: "u32"     u == unsign == 无符号整数(必须是正整数)
# 公式: 0 ~ (2 ** (32 - 1)) -1
# 结果: 0 ~  4294967295
const ROLLBACK_VERSION: i32 = 2;  
const PROGRAM_LANGUAGE: &'static str = "Rust";

fn main() {
    let hello = "Hello";
    println!("{} {}: {}!", hello, PROGRAM_LANGUAGE, ROLLBACK_VERSION);
}
数组数字常量
const DATA_TYPE_ARRAY: &'static [i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

fn main() {
    let hello = "Hello";
    println!("{} {:?}", hello, DATA_TYPE_ARRAY);
}



# 严谨的写法
const DATA_TYPE_ARRAY: &'static [i32; 10] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

fn main() {
    let hello = "Hello";
    println!("{} {:?}", hello, DATA_TYPE_ARRAY);
}
数组字符串常量
const DATA_TYPE_ARRAY: &'static [&'static str] = &["a", "b"];

fn main() {
    let hello = "Hello";
    println!("{} {:?}", hello, DATA_TYPE_ARRAY);
}



# 严谨的写法
const DATA_TYPE_ARRAY: &'static [&'static str; 2] = &["a", "b"];

fn main() {
    let hello = "Hello";
    println!("{} {:?}", hello, DATA_TYPE_ARRAY);
}
数组数组常量
# 数组中嵌套数组
const DATA_TYPE_ARRAY: [[i32; 2]; 2] = [[1, 2], [3, 4]];

fn main() {
    let hello = "Hello";
    println!("{} {:?}", hello, DATA_TYPE_ARRAY);
}



# 数组中嵌套元祖
const DATA_TYPE_ARRAY: [(&str, i32); 2] = [("a", 1), ("b", 2)];

fn main() {
    let hello = "Hello";
    println!("{} {:?}", hello, DATA_TYPE_ARRAY);
}
元祖字符串常量
const DATA_TYPE_ARRAY: (&str, &str, &str, i32, i32, i32) = ("a", "b", "c", 1, 2, 3);

fn main() {
    let hello = "Hello";
    println!("{} {:?}", hello, DATA_TYPE_ARRAY);
}



# 严谨的写法
const DATA_TYPE_ARRAY: (
    &'static str, &'static str, &'static str, i32, i32, i32
) = ("a", "b", "c", 1, 2, 3);

fn main() {
    let hello = "Hello";
    println!("{} {:?}", hello, DATA_TYPE_ARRAY);
}

 
 

循环

for循环数组(迭代)
# 错误的写法
fn main() {
    let a = [1, 2, 3, 4, 5, 6, 7, 8, 9];

    for i in a {
        println!("{}", i)
    }
}


# 正确的写法
fn main() {
    let a = [1, 2, 3, 4, 5, 6, 7, 8, 9];

    for i in a.iter() {
        println!("{}", i)
    }
}

for循环迭代对象(迭代)

# 1..9 == [1,2,3,4,5,6,7,8,9].iter()
# 1..9 == Iter(1,2,3,4,5,6,7,8,9)
# 1..9是一个迭代对象
fn main() {
    for i in 1..9 {
        println!("{}", i)
    }
}


# 反转数组迭代对象排列顺序
fn main() {
    for i in (1..9).rev() {
        println!("{:?}", i)
    }
}

# 排列顺序等同于下面的代码
fn main() {
    let a = [1,2,3,4,5,6,7,8,9];
    for i in a.iter().rev() {
        println!("{:?}", i)
    }
}
for循环continue关键字
# 从30开始打印
fn main() {
    let a = 1..100;
    for i in a {
        if i < 30 {
            continue
        }
        println!("{:?}", i)
    }
}
for循环break关键字
# 当大于30时,就退出循环
fn main() {
    let a = 1..100;
    for i in a {
        println!("{:?}", i);
        if i > 30 {
            break
        }
    }
}
while循环
# 当小于30时, 持续循环
fn main() {
    let mut a = 1;
    while a < 30 {
        println!("{}", a);
        a += 1
    }
}


# 当小于30时, 持续循环
fn main() {
    let mut a = 1;
    while true {
        if a < 30 {
            println!("{}", a);
        } else {
            break
        }
        a += 1
    }
}

loop循环
fn main() {
    let mut a = 1;
    loop {
        if a < 30 {
            println!("{}", a)
        }
        a += 1
    }
}

while true 和 loop 有什么区别?

从循环的角度看它们没有区别.
从编译器的角度看, while 后面时一个条件句的解析, 而loop则没有条件句的解析, 因此loop理论上要比while更快.
从程序员的角度看, while是用来做单个具体业务逻辑判断; 而loop则是用来做更宏观的模块代码设计使用, 把逻辑判断依托于抽象层去完成, 例如read_line获取用户输入来判断是否要继续或退出.

 
 

枚举

枚举是用来框定一个对象的所有属性定义, 确保程序在运行过程中涉及到该对象时, 输入输出是在定义范围内而不是超出预期之外的值.

枚举成员是特殊的类型值

枚举允许不它的成员不是一个intstrStringArrayTuple, 而可以是一个特殊的像是变量名称一样的标识.

#[derive(Debug)]        // trait
enum UserRole {         // 枚举对象
    Admin,              // 枚举成员
    Manager,            
    Employee
}


fn main() {
    let admin = UserRole::Admin;        // 枚举可以直接赋值
    let manager = UserRole::Manager;    
    let employee = UserRole::Employee;
    println!("{:?} {:?} {:?}", admin, manager, employee);
    println!("{:?}", UserRole::Admin);  // 枚举没有具体值,所以不存在所有权。
}
枚举匹配
#[derive(Debug)]
enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter,
}


fn value_in_cents(coin: Coin) -> i32 {
    match coin {
        Coin::Penny => {
            println!("Match Penny");
            1
        },
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter => 25,
    }
}


fn main() {
    println!("{:?}", value_in_cents(Coin::Penny))
}
枚举嵌套
#[derive(Debug)]      // trait
enum UsState {        // 枚举对象
    Alabama,          // 枚举成员
    Alaska,
}

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter(UsState),     // 枚举嵌套, 为Quarter这个枚举成员限定一个范围.
}

fn value_in_cents(coin: Coin) -> i32 {
    match coin {
        Coin::Penny => 1,
        Coin::Nickel => 5,
        Coin::Dime => 10,
        // 这里 state 可以随便定义,例如 abc
        Coin::Quarter(state) => {
            // 如果state变量发生变化, 引用时也要跟着对应起来.
            println!("State quarter from {:?}!", state);
            25
        },
    }
}

fn main() {
    println!("{:?}", value_in_cents(Coin::Penny));
    println!("{:?}", value_in_cents(Coin::Nickel));
    println!("{:?}", value_in_cents(Coin::Dime));
    println!("{:?}", value_in_cents(Coin::Quarter(UsState::Alabama)));
    println!("{:?}", value_in_cents(Coin::Quarter(UsState::Alaska)))
}
Some特殊枚举成员

标准的match写法

fn main() {
    let integer_ = Some(4u8);    // Some是核心库中的范型枚举
    match integer_ {
        Some(4) => println!("four"),
        _ => println!("unknown"),     // _也是核心库中的特殊枚举(意指: 其他)
    }
}

if let 表达式是一个match的一个缩写语法糖

fn main() {
    let integer_ = Some(4u8);
    if let Some(4) = integer_ {
        println!("four");
    }
}

if let ... else ... 表达式

fn main() {
    let integer_ = Some(4u8);
    if let Some(6) = integer_ {    // 这种语法糖简化了代码却可能会带来一定的风险.
        println!("four")                // 需开发人员自己权衡.
    } else {
        println!("unknown")
    }
}

 
 

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容