rust语法基础1
cargo basic
cargo new objname 创建项目
cargo run 运行项目
cargo install –force –path . 安装 .目录下的项目,将编译好的二进制文件拷贝到~/.cargo/bin中
变量绑定
Rust 中,使用关键字 let 声明变量。
let x = 5;
在 Rust 中,变量默认是不可改变的(immutable),当变量不可变时,一旦值被绑定到一个名称上,这个值就不能被改变,这样的设计有助于防止意外的数据修改和并发问题。若
要使得变量可变,需要在声明时使用 mut 关键字。
let mut x = 5;
x = 10;
常量
Rust 中常量总是不可变,声明常量使用 const 关键字而不是 let。
常量只能被声明为常量表达式,而不可以是其他任何只能在程序运行时计算出的值。
常量定义时候需要指定类型
const xx:i32 = 15;
标量类型
• 有符号整数(signed integers):i8、i16、i32、i64、i128 和 isize(指针宽度)
• 无符号整数(unsigned integers): u8、u16、u32、u64、u128 和 usize(指针宽度)
• 浮点数(floating point): f32、f64
• char(字符):单个 Unicode 字符,如 ‘a’,’α’ 和 ‘∞’(每个都是 4 字节)
• bool(布尔型):只能是 true 或 false
• 单元类型(unit type):()。其唯一可能的值就是 () 这个空元组
复合类型
数组
数组的类型定义为 [元素类型;元素数量] 在初始化时可以对每个元素都做一遍初始化[1,2,3,4,5],也可以用[值;数量]来做批量的初始化
let array:[i32;5] = [5;5];
数组的操作
array[0] //访问元素
array[0] = 1; //写数据 注意必须是通过mut关键字创建的数组才支持写数据
元组
let tup:(i32,i32,i32) = (1,2,3);
元组的成员是可以修改的,通过tup.0 tup.1 点+成员下标来访存
let mut tup:(i32,i32,i32) = (1,2,3);
tup.0 = 10;
println!("is {}",tup.0);
使用模式匹配解构元组
let mut tup:(i32,i32,i32) = (1,2,3); // 元组的定义
tup.0 = 10; // 访问 读写元组的元素,通过 元组名.idx去访问
println!("is {}",tup.0);
let (a,b,c) = tup; //模式匹配可以解构元组的值,将元组的值分配到几个变量上
函数定义
fn function_name() -> return_tpye{
do_someting
}
if表达式
if不需要写括号
if a > b {
}
if是一个表达式还可以有返回值 用于变量绑定语句
let if_a = if 1> 0 {100} else {10};
println!("{}",if_a);
loop循环
loop 关键字告诉 Rust 一遍又一遍地执行一段代码直到你明确要求停止。
可以通过continue跳过单次循环,可以通过break退出循环
let mut i = 100;
loop {
println!("{}",i);
i = i - 1;
if i < 1 {
break;
}
}
loop表达式有返回值就像if一样
let mut i = 100;
let s = loop {
println!("{}",i);
i = i - 1;
if i < 1 {
break 100;
}
};
println!("{}",s);
循环标签
loop可以存在循环标签,可以通过break和continue跳转到某个标签中,一般用于多层loop的情况
'loop1 : loop {
println!("loop1");
'loop2 : loop {
println!("loop2");
break 'loop1;
}
}
在loop关键字前使用 ‘循环标签名字 : 这样的表达式就可以给循环打标签,在break中需要 ‘循环标签名来实现跳转到某个loop循环标签中
while循环
let mut i = 0;
while i < 10 {
i = i + 1;
println!("i is{}",i)
}
while循环循环条件那没有括号,没有返回值0
for循环
for循环似乎主要用于遍历迭代器,实现了可迭代trait的对象就可以用for去迭代?
for i in 1..5{
println!("{}",i);
}
迭代数组
let test_array:[i32;10] = [2;10];
for i in test_array {
println!("{}",i);
}
所有权(ownership)
定义:
Rust 中的每一个值都有一个所有者(owner)
值在任一时刻有且只有一个所有者
当所有者(变量)离开作用域,这个值将被丢弃
如果某个对象实现了copy trait 在进行变量绑定操作时候会直接复制对象的值过去,而不是会转移所有权
所有权机制就是为了保证在某一段时间内,某个值只有一个所有者,为了避免数据竞争
这个表达式的行为是 将123绑定到符号x,然后再次绑定到y中,由于值在任意时刻只有一个所有者,x会被丢弃
let x = 123;
let y = x;
变量隐藏
这个样例中 第一个变量被第二个 隐藏(Shadowing) 了
fn main() {
let x = 5;
let x = x + 1;
{
let x = x * 2;
println!("The value of x in the
inner scope is: {x}");
}
println!("The value of x is: {x}");
}
函数传参会转移所有权
s作为参数传递到 test函数时,所有权被转移到test中
fn test(a:String) -> String {
return a;
}
fn main() {
let s = String::from("hello");
test(s);
println!("{}",s);
}
函数返回值也会转移所有权
引用和借用
引用(reference)像一个指针,因为它是一个地址,我们可以由此访问储存于该地址的属于其他变量的数据。 与指针不同,引用确保指向某个特定类型的有效值,我们将创建一个引用的行为称为 借用(borrowing)。
传递引用并不会转移所有权
fn test(a:&String){
println!("{}",a);
}
fn main() {
let s = String::from("hello");
test(&s);
println!("{}",s);
}
可变引用
可变引用可以在引用的基础上传递一个可以读写数据的”指针”,而不转移数据的所有权
同一作用域下可以存在多个对于同一对象的不可变引用,但是不能存在多个对于同一对象可变引用,不然可能会产生数据竞争,也不能同时存在对于同一对象的可变引用和不可变引用
fn test(a:&mut String){
a.push_str("AAAAAAA");
println!("{}",a);
}
fn main() {
let mut s = String::from("hello");
test(&mut s);
println!("{}",s);
}
String类型
String类型支持两种创建方式
通过String::from创建 通过”aaa”.to_string() 字符串字面量类型转换创建
fn main() {
let s1 = String::from("tests1");
let s2 = "tests2".to_string();
println!("{}",s1);
println!("{}",s2);
}
slice类型
slice可以创建一个针对某个集合的一段不可变引用,它并没有获取这段数据的所有权
fn main() {
let a = [1, 2, 3, 4, 5];
let slice = &a[1..3];
let str = String::from("test_str1");
let str2 = &str[0..3];
println!("{}",str2);
}
struct结构体
struct的创建方式是 struct 结构体名然后在花括号里面定义结构体有的字段
struct test_struct {
a: i32
b: i64
}
结构体实例创建,访问字段
struct User{
Username:String,
Password:String
}
fn main() {
let mut User1 = User{
Username : "User1".to_string(),
Password : "123456".to_string()
};
User1.Username = String::from("User2");
println!("{}",User1.Username);
}
元组结构体
元组结构体也是一种能将不同数据绑定在一起的一个复合类型,和结构体的区别是元组结构体的成员没有一个具体的字段名
元组结构体的创建 struct 元组结构体名 然后在圆括号中定义数据成员
struct Color(i32,i32,i32);
fn main() {
let mut black = Color(255,255,255);
println!("{}",black.0);
black.0 = 0;
println!("{}",black.0);
}
rustlings Exercise
variables §3.1
functions §3.3
if §3.5
primitive_types §3.2, §4.3
vecs §8.1
move_semantics §4.1, §4.2
structs §5.1, §5.3
strings §8.2
struct1
// structs1.rs
//
// Address all the TODOs to make the tests pass!
//
// Execute `rustlings hint structs1` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
struct ColorClassicStruct {
// TODO: Something goes here
red:u8,
green:u8,
blue:u8
}
struct ColorTupleStruct(/* TODO: Something goes here */u8,u8,u8);
#[derive(Debug)]
struct UnitLikeStruct;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn classic_c_structs() {
// TODO: Instantiate a classic c struct!
// let green =
let green:ColorClassicStruct = ColorClassicStruct{
red:0,
green:255,
blue:0
};
assert_eq!(green.red, 0);
assert_eq!(green.green, 255);
assert_eq!(green.blue, 0);
}
#[test]
fn tuple_structs() {
// TODO: Instantiate a tuple struct!
// let green =
let green = ColorTupleStruct(0,255,0);
assert_eq!(green.0, 0);
assert_eq!(green.1, 255);
assert_eq!(green.2, 0);
}
#[test]
fn unit_structs() {
// TODO: Instantiate a unit-like struct!
// let unit_like_struct =
let unit_like_struct = UnitLikeStruct{};
let message = format!("{:?}s are fun!", unit_like_struct);
assert_eq!(message, "UnitLikeStructs are fun!");
}
}
struct2
// structs2.rs
//
// Address all the TODOs to make the tests pass!
//
// Execute `rustlings hint structs2` or use the `hint` watch subcommand for a
// hint.
#[derive(Debug)]
struct Order {
name: String,
year: u32,
made_by_phone: bool,
made_by_mobile: bool,
made_by_email: bool,
item_number: u32,
count: u32,
}
fn create_order_template() -> Order {
Order {
name: String::from("Bob"),
year: 2019,
made_by_phone: false,
made_by_mobile: false,
made_by_email: true,
item_number: 123,
count: 0,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn your_order() {
let order_template = create_order_template();
// TODO: Create your own order using the update syntax and template above!
// let your_order =
let mut your_order = Order {
name : String::from("Hacker in Rust"),
year : 2019,
made_by_phone : false,
made_by_mobile : false,
made_by_email : true,
item_number : 123,
count : 1
};
assert_eq!(your_order.name, "Hacker in Rust");
assert_eq!(your_order.year, order_template.year);
assert_eq!(your_order.made_by_phone, order_template.made_by_phone);
assert_eq!(your_order.made_by_mobile, order_template.made_by_mobile);
assert_eq!(your_order.made_by_email, order_template.made_by_email);
assert_eq!(your_order.item_number, order_template.item_number);
assert_eq!(your_order.count, 1);
}
}
struct3
https://kaisery.github.io/trpl-zh-cn/ch05-03-method-syntax.html
结构体方法定义
结构体方法类似于函数,也是使用fn xxname来定义,不同的地方是他们第一个参数总是 &self 或者 &mut self 用于代表该方法的实例
为某个结构体添加结构体方法通过 impl语法块实现
impl struct_name {
fn xxfunc(&self or &mut self){
dosometing
}
}
e.g.
struct Rectangle {
width:u32,
height:u32
}
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}
// structs3.rs
//
// Structs contain data, but can also have logic. In this exercise we have
// defined the Package struct and we want to test some logic attached to it.
// Make the code compile and the tests pass!
//
// Execute `rustlings hint structs3` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
#[derive(Debug)]
struct Package {
sender_country: String,
recipient_country: String,
weight_in_grams: i32,
}
impl Package {
fn new(sender_country: String, recipient_country: String, weight_in_grams: i32) -> Package {
if weight_in_grams <= 0 {
panic!("Can not ship a weightless package.")
} else {
Package {
sender_country,
recipient_country,
weight_in_grams,
}
}
}
// fn is_international(&self) -> ??? {
// // Something goes here...
// }
fn is_international(&self) -> bool {
if self.sender_country == "Canada"{
false
}
else{
true
}
}
// fn get_fees(&self, cents_per_gram: i32) -> ??? {
// // Something goes here...
// }
fn get_fees(&self, cents_per_gram: i32) -> i32 {
self.weight_in_grams * cents_per_gram
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[should_panic]
fn fail_creating_weightless_package() {
let sender_country = String::from("Spain");
let recipient_country = String::from("Austria");
Package::new(sender_country, recipient_country, -2210);
}
#[test]
fn create_international_package() {
let sender_country = String::from("Spain");
let recipient_country = String::from("Russia");
let package = Package::new(sender_country, recipient_country, 1200);
assert!(package.is_international());
}
#[test]
fn create_local_package() {
let sender_country = String::from("Canada");
let recipient_country = sender_country.clone();
let package = Package::new(sender_country, recipient_country, 1200);
assert!(!package.is_international());
}
#[test]
fn calculate_transport_fees() {
let sender_country = String::from("Spain");
let recipient_country = String::from("Spain");
let cents_per_gram = 3;
let package = Package::new(sender_country, recipient_country, 1500);
assert_eq!(package.get_fees(cents_per_gram), 4500);
assert_eq!(package.get_fees(cents_per_gram * 2), 9000);
}
}
String1
// strings1.rs
//
// Make me compile without changing the function signature!
//
// Execute `rustlings hint strings1` or use the `hint` watch subcommand for a
// hint.
fn main() {
let answer = current_favorite_color();
println!("My current favorite color is {}", answer);
}
fn current_favorite_color() -> String {
"blue".to_string()
}
String2
// strings2.rs
//
// Make me compile without changing the function signature!
//
// Execute `rustlings hint strings2` or use the `hint` watch subcommand for a
// hint.
fn main() {
let word = String::from("green"); // Try not changing this line :)
if is_a_color_word(&word) {
println!("That is a color word I know!");
} else {
println!("That is not a color word I know.");
}
}
fn is_a_color_word(attempt: &str) -> bool {
attempt == "green" || attempt == "blue" || attempt == "red"
}
String3
// strings3.rs
//
// Execute `rustlings hint strings3` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
fn trim_me(input: &str) -> String {
// TODO: Remove whitespace from both ends of a string!
input.trim().to_string()
}
fn compose_me(input: &str) -> String {
// TODO: Add " world!" to the string! There's multiple ways to do this!
let mut result = input.to_string();
result.push_str(" world!");
result
}
fn replace_me(input: &str) -> String {
// TODO: Replace "cars" in the string with "balloons"!
let result = input.replace("cars", "balloons");
result
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn trim_a_string() {
assert_eq!(trim_me("Hello! "), "Hello!");
assert_eq!(trim_me(" What's up!"), "What's up!");
assert_eq!(trim_me(" Hola! "), "Hola!");
}
#[test]
fn compose_a_string() {
assert_eq!(compose_me("Hello"), "Hello world!");
assert_eq!(compose_me("Goodbye"), "Goodbye world!");
}
#[test]
fn replace_a_string() {
assert_eq!(replace_me("I think cars are cool"), "I think balloons are cool");
assert_eq!(replace_me("I love to look at cars"), "I love to look at balloons");
}
}
String4
// strings4.rs
//
// Ok, here are a bunch of values-- some are `String`s, some are `&str`s. Your
// task is to call one of these two functions on each value depending on what
// you think each value is. That is, add either `string_slice` or `string`
// before the parentheses on each line. If you're right, it will compile!
//
// No hints this time!
// I AM NOT DONE
fn string_slice(arg: &str) {
println!("{}", arg);
}
fn string(arg: String) {
println!("{}", arg);
}
fn main() {
string_slice("blue");
string("red".to_string());
string(String::from("hi"));
string("rust is fun!".to_owned());
string_slice("nice weather".into());
string(format!("Interpolation {}", "Station"));
string_slice(&String::from("abc")[0..1]);
string_slice(" hello there ".trim());
string("Happy Monday!".to_string().replace("Mon", "Tues"));
string("mY sHiFt KeY iS sTiCkY".to_lowercase());
}