提交 a3dafd5d 编写于 作者: L LiGuoBin

add rust module

上级 1d4b87b8
......@@ -14,8 +14,8 @@ subprojects {
repositories {
maven { url "http://repo.maven.apache.org/maven2" }
//强制HTTPS了
maven { url "https://repo.maven.apache.org/maven2" }
}
sourceSets {
......
//导入子模块的东东
pub mod hosting;
//Rust会查找 src/hosting.rs(同名文件) 或者 src/hosting/mod.rs,mod不再包含子模块则使用src/hosting.rs,否则使用src/hosting/mod.rs
pub fn add_to_waitlist() {
hosting::add_to_waitlist_host();
}
\ No newline at end of file
//hosting是front_of_house的子模块,hosting在front_of_house的文件夹里面
pub fn add_to_waitlist_host() {
println!("hello world aaaaaaaaaaaa")
}
\ No newline at end of file
//use crate::front_of_house::front_of_house.hosting;
//use front_of_house::front_of_house.hosting; //使用相对路径
//use crate::front_of_house::front_of_house.hosting::add_to_waitlist; //将函数直接导入,使用add_to_waitlist即可调用了
/// 使用cargo new --lib restaurant 命令创建新的
/// Cargo遵循一个约定,即src/main.rs是与包同名的二进制板条箱的板条箱根。(crate翻译为板条箱或者木箱?暂时不确定转义术语)
/// 同样,Cargo知道如果包目录包含src/lib.rs,则包包含与包同名的库板条箱,src/lib.rs是其板条箱根目录。Cargo将板条箱根文件传递给rustc以构建库或二进制文件。
/// crate是Rust 中的基本编译单元,可以被编译为可执行文件或库,一个crate是一个文件
pub mod front_of_house;
//以mod关键字开头定义模块,然后指定模块名称,内部可以继续定义mod,该模块在板条箱的模块结构的根目录下被命名为模块树。
//mod front_of_house {
// //直接编译会报错,因为模块中所有的东西都是私有的,虽然使用pub公开路径,但是公开模块不会公开模块的内容,所以里面的函数仍是私有的。编译仍会报错
// pub mod front_of_house.hosting {
// //根据上述规则,需要在函数上加pub才能使得该函数被外部访问到
// pub fn add_to_waitlist() {}
//
// fn seat_at_table() {}
// }
//
// mod serving {
// fn take_order() {}
//
// fn serve_order() {}
//
// fn take_payment() {}
// }
//
// //绝对路径 crate
// //相对路径 self、super,后面均使用 ::
//}
//使用 pub公开模块的功能
pub fn eat_at_restaurant() {
// 使用绝对路径,更好
// crate::front_of_house::hosting::add_to_waitlist_host();
// 使用相对路径
front_of_house::hosting::add_to_waitlist_host();
}
fn serve_order() {}
mod back_of_house {
fn fix_incorrect_order() {
cook_order();
//该模块的父模块,在这里实际是crate根,当这部分代码有在未来可能同时移动,则不需要更改代码
super::serve_order();
}
fn cook_order() {}
//公开结构体不会公开其所有的属性
pub struct Breakfast {
pub toast: String,
//该结构是公开的,且只有toast是公开的属性字段
seasonal_fruit: String,//无法更改
}
impl Breakfast {
//需要使用关联函数生成 结构体Breakfast的示例,因为其字段有些是私有的,无法在外部生成
pub fn summer(toast: &str) -> Breakfast {
Breakfast {
toast: String::from(toast),
seasonal_fruit: String::from("peaches"),
}
}
}
//公开枚举将会公开枚举的所有值
pub enum Appetizer {
Soup,
Salad,
}
}
//mod front_of_house;//在mod front_of_house之后使用分号(而不是使用块)会告诉Rust从另一个与模块同名的文件中加载模块的内容。
//重新导出,使名称可用于新范围内的任何代码 (因为我们将一个项目放入范围内,同时也使该项目可供其他人进入其范围)
//use std::collections::*; //导入所有内部的类型
pub fn eat_at_restaurant2() {
let mut meal = back_of_house::Breakfast::summer("Rye");//关联函数 summer 用于构造实例
meal.toast = String::from("Wheat");
println!("I'd like {} toast please", meal.toast);
//下面编译不过,seasonal_fruit是私有的
//meal.seasonal_fruit = String::from("blueberries");
//使用公开的枚举类型
let order1 = back_of_house::Appetizer::Soup;
let order2 = back_of_house::Appetizer::Salad;
//使用use导入模块,可以省略模块前缀,使代码简洁
front_of_house::hosting::add_to_waitlist_host();//front_of_house :: hosting 二级包
front_of_house::hosting::add_to_waitlist_host();
front_of_house::hosting::add_to_waitlist_host();
//use的习惯用法,但是不同模块中的相同函数,需要加模块前缀,如:fmt::Result,io::Result
use std::collections::HashMap as RustHashMap;//使用as为导入的类型提供别名,一般在最前面使用导入,这里为了方便
let mut map = RustHashMap::new();
map.insert(1, 2);
}
\ No newline at end of file
......@@ -9,11 +9,12 @@ use rand::Rng;
/// 引用和借用:https://dreamylost.cn/rust/Rust-Rust%E5%AD%A6%E4%B9%A0%E4%B9%8B%E5%BC%95%E7%94%A8%E4%B8%8E%E5%80%9F%E7%94%A8.html
/// 所有权:https://dreamylost.cn/rust/Rust-%E6%89%80%E6%9C%89%E6%9D%83.html
/// 切片:https://dreamylost.cn/rust/Rust-%E5%88%87%E7%89%87.html
fn main() {
println!("Hello, world!");
variables();
variables_function();
println!("====================");
data_type();
simple_array_data_type();
println!("====================");
another_function(12);
println!("====================");
......@@ -21,13 +22,13 @@ fn main() {
println!("====================");
println!("{}", five());//打印字符串,不能直接println!(five())
println!("====================");
branchs();
control_function();
println!("====================");
println!("斐波那契第20项是:{}", fib(20));
println!("====================");
println!("斐波那契第20项是:{}", fib_2(20));
println!("====================");
string_from();
string_function();
println!("====================");
return_function();
println!("====================");
......@@ -37,28 +38,437 @@ fn main() {
println!("====================");
point_function();
println!("====================");
try_change();
try_change_function();
println!("====================");
empty_point();
guessing_game();
empty_point_function();
println!("====================");
struct_data_type();
println!("====================");
method_syntax();
println!("====================");
enum_data_type();
println!("====================");
match_syntax();
match_syntax2();
println!("====================");
crate_function();
println!("====================");
example_guessing_game();
}
pub mod front_of_house;
//引用外部的条板箱
fn crate_function() {
front_of_house::add_to_waitlist()
}
//pub mod lib;
//
//fn crate_function_lib() {
// lib::eat_at_restaurant();
// lib::eat_at_restaurant2();
//}
//简洁的控制流语法
fn match_syntax2() {
let some_u8_value = Some(0u8);
match some_u8_value {
Some(3) => println!("three"),
_ => () //这行是多余的样板代码
}
//使用if let 省略上面的样板代码
if let Some(3) = some_u8_value {
println!("three");
}
#[derive(Debug)]
enum UsState {
Alabama,
Alaska,
}
enum Coin {
Penny,
Nickel,
Dime,
Quarter(UsState),
}
//使用if let简化代码
fn value_in_cents(coin: Coin) -> u8 {
let mut count = 0;
if let Coin::Quarter(state) = coin {
println!("State quarter from {:?}!", state);
} else {
count += 1;
}
1
}
}
fn match_syntax() {
//枚举与match
enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
fn value_in_cents2(coin: Coin) -> u8 {
match coin {
Coin::Penny => {
//代码多时需要使用花括号,并且最后一行返回值不加分号。大括号后面仍是逗号
println!("Lucky penny!");
1
},
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
//绑定到值的匹配
#[derive(Debug)]
enum UsState {
Alabama,
Alaska,
}
enum Coin2 {
Penny,
Nickel,
Dime,
Quarter(UsState),
}
fn value_in_cents3(coin: Coin2) -> u8 {
match coin {
Coin2::Penny => 1,
Coin2::Nickel => 5,
Coin2::Dime => 10,
Coin2::Quarter(state) => {
println!("State quarter from {:?}!", state);
25
},
}
}
//Option类型match
fn plus_one(x: Option<i32>) -> Option<i32> {
match x {
//这行代码多余,但是又不能省略,否则编译报错。
None => None,
Some(i) => Some(i + 1),
}
}
let five = Some(5);
let six = plus_one(five);
let none = plus_one(None);
//使用占位符,编译通过
let some_u8_value = 0u8;
match some_u8_value {
1 => println!("one"),
3 => println!("three"),
5 => println!("five"),
7 => println!("seven"),
_ => ()
}
}
fn enum_data_type() {
//定义枚举类型
enum IpAddrKind {
V4,
V6,
}
//使用
let four = IpAddrKind::V4;
let six = IpAddrKind::V6;
fn route(ip_kind: IpAddrKind) {}
//两个值IpAddrKind::V4和IpAddrKind::V6都具有相同的类型: IpAddrKind
route(IpAddrKind::V4);
route(IpAddrKind::V6);
struct IpAddr {
//在结构体中使用枚举
kind: IpAddrKind,
address: String,
}
let home = IpAddr {
kind: IpAddrKind::V4,
address: String::from("127.0.0.1"),
};
let loopback = IpAddr {
kind: IpAddrKind::V6,
address: String::from("::1"),
};
//数值直接放入每个枚举变量中,而不是需要使用结构体 struct IpAddr
enum IpAddr2 {
V4(String),
V6(String),
}
let home = IpAddr2::V4(String::from("127.0.0.1"));
let loopback = IpAddr2::V6(String::from("::1"));
//将枚举数值定义为不同类型,此时struct IpAddr无法实现
enum IpAddr3 {
V4(u8, u8, u8, u8),
V6(String),
}
let home = IpAddr3::V4(127, 0, 0, 1);
let loopback = IpAddr3::V6(String::from("::1"));
//使用枚举
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
//使用结构体
struct QuitMessage; // 单位结构
struct MoveMessage {
x: i32,
y: i32,
}
struct WriteMessage(String); // 元祖结构
struct ChangeColorMessage(i32, i32, i32); // 元祖结构
//定义一个impl即可对所有枚举值生效,他们都能调用call
impl Message {
fn call(&self) {
// do something
}
}
let m = Message::Write(String::from("hello"));
m.call();
//Option类型
let some_number = Some(5);
let some_string = Some("a string");
//为None时需要指定类型,否则无法推断出类型
let absent_number: Option<i32> = None;
let x: i8 = 5;
let y: Option<i8> = Some(5);
//Option<i8> 与 i8 是不同的类型 <>是泛型,Option<T>表示任意的类型都可以放进Option
//let sum = x + y;
}
//下面为了编译,将错误或多余代码注释了。
fn method_syntax() {
//方法语法,方法与函数不同
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
//结构体的实现块,方法第一个参数必须是&self,不需要声明类型(impl与struct名称相同,能自动推断self类型,这也是能自动引用、取消引用的原因)
impl Rectangle {
//把2个方法放在多个impl实现也是可以的
fn area(&self) -> u32 {
self.width * self.height
}
//新增方法,有额外参数
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
//关联函数,没有self,类似其他语言的静态方法,但不是rust方法
fn square(size: u32) -> Rectangle {
Rectangle { width: size, height: size }
}
}
let rect1 = Rectangle { width: 30, height: 50 };
//c/c++中如果object是一个指针, object->something() 与 (*object).something()等价
//Rust没有等效于->运算符;相反,Rust具有称为自动引用和取消引用的功能。调用方法是Rust少数具有这种行为的地方之一。
//工作原理如下:当您使用object.something()调用方法时,Rust会自动添加&,&mut或*,从而使对象与方法的签名匹配。换句话说,以下是相同的:
//p1.distance(&p2);
//(&p1).distance(&p2);
println!(
"The area of the rectangle is {} square pixels.",
rect1.area()
);
//方法参数
let rect1 = Rectangle { width: 30, height: 50 };
let rect2 = Rectangle { width: 10, height: 40 };
let rect3 = Rectangle { width: 60, height: 45 };
println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2));
println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3));
//impl块的另一个有用功能是允许我们在不以self为参数的impl块中定义函数。这些之所以称为关联函数,是因为它们与struct相关联。
//它们仍然是函数,而不是方法,因为它们没有可使用的结构实例
//关联函数通常用于将返回该结构的新实例的构造函数。例如,我们可以提供一个关联的函数,该函数将具有一个维度参数并将其用作宽度和高度,从而使创建矩形矩形变得更加容易,而不必两次指定相同的值:
let sq = Rectangle::square(3);//类似调用静态方法
println!("sq is {:#?}", sq);
//关联函数与结构体相关,但是没有self实例,他们仍是函数!!!
struct Test;
impl Test {
fn test() -> String {
String::from("hello world")
}
}
let test = Test::test();
println!("test is {:#?}", test);
}
fn struct_data_type() {
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}
let mut user1 = User { //必须定义为可变的才能修改结构体的内容
email: String::from("someone@example.com"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};
user1.email = String::from("anotheremail@example.com");
fn empty_point() {
//对应参数名和结构体属性名称相同的,可以省略以减少代码
fn build_user(email: String, username: String) -> User {
User {
email: email,
username: username,
active: true,
sign_in_count: 1,
}
}
//更好的方法是省略参数名,结构体没有顺序要求,与元祖不同,元祖结构体:仅声明类型的结构体
fn build_user_better(email: String, username: String) -> User {
User {
email,
username,
active: true,
sign_in_count: 1,
}
}
//创建一个新的结构体user2,并使用user1的某些值
let user2 = User {
email: String::from("another@example.com"),
username: String::from("anotherusername567"),
active: user1.active,
sign_in_count: user1.sign_in_count,
};
//更好的方式是使用 ..语法,其余字段应与给定实例(user1)中的字段具有相同的值
let user2 = User {
email: String::from("another@example.com"),
username: String::from("anotherusername567"),
..user1
};
//元祖结构体,没有命名属性字段,仅有类型声明
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
//此结构体存储切片。而上面的结构体存储的是String类型,下面代码编译会报错,因为使用切片时需要指定生命周期。与使用String拥有所有权不同,&str没有获取所有权而只是借用
// struct User2 {
// username: &str,
// email: &str,
// sign_in_count: u64,
// active: bool,
// }
let width1 = 30;
let height1 = 50;
fn area(width: u32, height: u32) -> u32 {
width * height
}
// let reference_to_nothing = dangle();
println!("The area of the rectangle is {} square pixels.", area(width1, height1));
//使用元祖
fn area_tuple(dimensions: (u32, u32)) -> u32 {
dimensions.0 * dimensions.1
}
let rect1 = (30, 50);
println!(
"The area of the rectangle is {} square pixels.",
area_tuple(rect1)
);
//使用结构体赋予更多含义
#[derive(Debug)] //使得该结构体能在println!中被打印
struct Rectangle {
width: u32,
height: u32,
}
fn area_struct(rectangle: &Rectangle) -> u32 {
rectangle.width * rectangle.height
}
let rect1 = Rectangle { width: 30, height: 50 };
println!(
"The area of the rectangle is {} square pixels.",
area_struct(&rect1)
);
//这将会报错,因为该结构体不支持显示:`Rectangle` doesn't implement `std::fmt::Display`
println!("rect1 is {:#?}", rect1);//{:?}使用调试模式打印也会报错:`Rectangle` doesn't implement `std::fmt::Debug`,{:#?} 格式化打印
}
fn empty_point_function() {
//let reference_to_nothing = dangle();
let reference_to_nothing = no_dangle();
fn no_dangle() -> String {
String::from("hello")// 直接反回函数的值,不能加分号
}
//编译报错,因为s是在dangle内部创建的,所以当dangle的代码完成时,将释放s。但是我们试图返回对它的引用。这意味着该引用将指向无效的String。Rust不允许我们这样做。
// fn dangle() -> &String {
// let s = String::from("hello");
// &s
// }
// fn dangle() -> &String {
// let s = String::from("hello");
// &s
// }
}
fn try_change() {
fn try_change_function() {
//必须都是mut的,否则编译就会报错,不可变,无法被改变
fn change(some_string: &mut String) {
some_string.push_str(", world");
......@@ -69,8 +479,8 @@ fn try_change() {
let mut s = String::from("hello");
let r1 = &mut s;
// let r2 = &mut s;//可变引用只能被出借一次,这里将会编译报错
// println!("{}, {}", r1, r2);
//let r2 = &mut s;//可变引用只能被出借一次,这里将会编译报错
//println!("{}, {}", r1, r2);
let mut s = String::from("hello");
......@@ -81,10 +491,10 @@ fn try_change() {
let mut s = String::from("hello");
let r1 = &s; // 没问题,与上面两次mut出借不一样,这里是没有mut,所以对于不可变引用,可以使用多次次,且不可在拥有不可变引用时同时拥有可变引用
let r2 = &s; // 没问题
// let r3 = &mut s; // 有问题,不可变在后面却是可变,不允许,编译报错
// println!("{}, {}, and {}", r1, r2, r3);
let r1 = &s; // 没问题,与上面两次mut出借不一样,这里是没有mut,所以对于不可变引用,可以使用多次次,且不可在拥有不可变引用时同时拥有可变引用
let r2 = &s; // 没问题
//let r3 = &mut s; // 有问题,不可变在后面却是可变,不允许,编译报错
//println!("{}, {}, and {}", r1, r2, r3);
let mut s = String::from("hello");
......@@ -92,7 +502,7 @@ fn try_change() {
let r1 = &s; // 没问题
let r2 = &s; // 没问题
println!("{} and {}", r1, r2);
// 在此之后不再使用r1和r2
//在此之后不再使用r1和r2
let r3 = &mut s; // 没问题,因为r1 r2进入println! 并且在此之后会失效,与所有权有关。
println!("{}", r3);
......@@ -133,7 +543,7 @@ fn tuple_function() {
}
fn return_function() {
let s1 = gives_ownership(); // lets_ownership移动其返回值到s1中
let s1 = gives_ownership(); // lets_ownership移动其返回值到s1中
let s2 = String::from("hello"); // s2进入范围
......@@ -147,11 +557,11 @@ fn return_function() {
// take_and_gives_back将获取一个String并返回一个
fn takes_and_gives_back(a_string: String) -> String { // a_string进入范围
a_string // 返回a_string并移至调用函数
a_string // 返回a_string并移至调用函数
}
}
fn string_from() {
fn string_function() {
let mut s = String::from("hello");
s.push_str(", world!"); // push_str() 将文字附加到字符串
......@@ -160,11 +570,11 @@ fn string_from() {
let s = String::from("hello"); // s进入范围
takes_ownership(s); // s的值移动到函数,所以在这里不再有效
// println!("{}", s);//编译错误:value borrowed here after move。出借后的s被移动,后续不可用
takes_ownership(s); // s的值移动到函数,所以在这里不再有效
//println!("{}", s);//编译错误:value borrowed here after move。出借后的s被移动,后续不可用
let x = 5; // x进入范围
makes_copy(x); // x将移动到函数
let x = 5; // x进入范围
makes_copy(x); // x将移动到函数
// 但是i32是Copy,所以之后还可以使用
println!("{}", x);//正常打印
......@@ -204,7 +614,7 @@ fn fib_2(n: i32) -> i32 {
}
//控制流
fn branchs() {
fn control_function() {
let number = 3;
//表达式结果必须是bool类型,不像c会自动将非bool转化为bool
if number < 5 {
......@@ -290,7 +700,6 @@ fn branchs() {
println!("LIFTOFF!!!");
}
//具有返回值的rust函数
fn five() -> i32 {
//这里同样,由于需要返回值为i32类型,增加了分号表示语句,没有返回值(实际是空括号),所以导致类型不一致,编译会报错
......@@ -318,7 +727,7 @@ fn another_function(x: i32) {
}
//rust不关注函数与main的顺序问题
fn data_type() {
fn simple_array_data_type() {
//--release模式下,整数溢出将会变为最小值
//在u8(0-255)类型下,256变为0,257变为1,依此类推
......@@ -383,7 +792,7 @@ fn data_type() {
let element = a[0];//若下标大于数组索引则运行时检查并报错退出"error: index out of bounds: the len is 5 but the index is 10"
}
fn variables() {
fn variables_function() {
//默认i32,带符号32位整数
let x = 5;
println!("The value of x is: {}", x);
......@@ -412,13 +821,13 @@ fn variables() {
println!("The value of x is: {}", i);
}
fn guessing_game() {
fn example_guessing_game() {
println!("Guess the number!");
//thread_rng一个在当前执行线程本地且由操作系统播种的随机数生成器
let secret_number = rand::thread_rng().gen_range(1, 101);
// println!("The secret number is: {}", secret_number);
//println!("The secret number is: {}", secret_number);
loop {
println!("Please input your guess.");
......@@ -434,7 +843,7 @@ fn guessing_game() {
//Rust允许我们用新的值遮盖以前的值guess。此功能通常用于要将值从一种类型转换为另一种类型的情况。
//阴影使我们可以重用guess变量名,而不是强迫我们创建两个唯一变量,例如guess_str和guess。
//前面的guess是可变的,这个是不可变的。
// let guess: u32 = guess.trim().parse().expect("Please type a number!");//类型不明确,必须指定具体类型
//let guess: u32 = guess.trim().parse().expect("Please type a number!");//类型不明确,必须指定具体类型
//println!是宏
println!("You guessed: {}", guess);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册