虽然Rust工作上不一定用到,目前很难靠这个吃饭。但因为下面几个原因,有必要了解下Rust:
现在的Rust生态的体量太小,和Java,Go的生态比还不值一提。但在云原生,web框架,中间件以及应用领域也已经有了些明星项目。比如:
Rust目前在嵌入式,机器人,云原生几个重点领域有广阔发展前景。操作系统和操作系统相关也有很多项目:
仅从语言的外观找出些特性。本篇并非深入研究Rust。
Rust没有其他语言的null,因为当尝试使用非Null值那样使用Null值,就会引起错误。这是个Billion dollar mistake。
虽然Rust中没有Null这个东西,但Rust中有Null这个概念,Rust提供拥有Null这个概念:Option<T>
。
如下面的代码第二个guess是个全新的变量,只是和之前的guess变量同名,若不加let是用的第一个guess。用了let第二个变量将第一个覆盖了。
let mut guess = String::new();io::stdin().read_line(&mut guess).expect("无法读取行");let guess:u32 = match guess.trim().parse(){
Ok(num) => num,
Err(_) => continue,}
没有mut修饰的变量是不可变,有mut修饰的是可变。
println!不是函数,而是macro宏。使用!来区分它们与普通方法调用。
Rust语言在特定的作用域内,只能有一个可变的引用。可以用于在编译时防止数据竞争。例如:
fn main() {
let mut s = String::from("hello");
let s1 = &mut s;
let s2 = &mut s;
println!("{}, {}",s1, s2)}
上面的代码在编译时候就会报错:Cannot borrow
s
as mutable more than once at a time
其他语言会发生:一个指针引用了内存中的某个地址,而这块内存可能已经释放并另作他用了。在Rust里,编译器可保证不出现此类情况。例如下面的代码s出了函数作用域会被销毁,但是返回了一个对被销毁对象的引用,编译不会通过,提示缺少生命周期说明符:
fn dangle() -> &String {
let s = String::from("hello");
return &s;}
上面的代码在编译时候就会报错:Missing lifetime specifier
#[derive(Debug)]struct Rectangle {
width: u32,
length: u32,}fn main() {
let rect = Rectangle {
width: 30,
length: 50,
};
println!("{}", area(&rect));
println!("{:#?}", rect);}fn area(rect: &Rectangle) -> u32 {
rect.width * rect.length}
#[derive(Debug)]struct Rectangle {
width: u32,
length: u32,}impl Rectangle {
fn area(&self) -> u32 {
self.width * self.length }}fn main() {
let rect = Rectangle {
width: 30,
length: 50,
};
println!("{}", rect.area());
println!("{:#?}", rect);}
#[derive(Debug)]struct Rectangle {
width: u32,
length: u32,}impl Rectangle {
fn area(&self) -> u32 {
self.width * self.length }
fn square(size: u32) -> Rectangle {
Rectangle {
width: size,
length: size,
}
}}fn main() {
let s = Rectangle::square(20);
println!("{:#?}", s);
let rect = Rectangle {
width: 30,
length: 50,
};
println!("{}", rect.area());
println!("{:#?}", rect);}
Option<T>
类
的功能fn main() {
let mut v = vec![1,2,3,4,5];
let first = &v[0];
v.push(6);
println!("The first element is {}", first);}
编译报错:
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
--> src\main.rs:4:5 |3 | let first = &v[0];
| - immutable borrow occurs here4 | v.push(6);
| ^^^^^^^^^ mutable borrow occurs here5 | println!("The first element is {}", first);
| ----- immutable borrow later used here
vec这种数据类型是放在heap上的,在内存中的摆放是连续的。所以在往vec添加一个元素时,在内存中就可能没有这么大的连续内存块了,Rust这时就把内存重新分配下,再找个足够大的内存来存放这个添加了元素之后的vec,这样原来的内存会被释放和重新分配,而上面代码的first仍然指向原来的地址,这样程序就出问题了。Rust的借用规则在编译时就可以防止这种情况发生。
use std::collections::HashMap;fn main() {
let text = "hello world wonderfull world";
let mut map = HashMap::new();
for word in text.split_whitespace() {
let count = map.entry(word).or_insert(0);
*count += 1;
}
print!("{:#?}", map);}
use std::fs::File;use std::io::ErrorKind;fn main() {
let f = File::open("hello.txt").unwrap_or_else(|error| {
if error.kind() == ErrorKind::NotFound {
File::create("hello.txt").unwrap_or_else(|error| {
panic!("Error creating file: {:?}", error);
})
} else {
panic!("Error opening file: {:?}", error);
}
});}
除了可以在函数中处理错误外,还可以将错误返回给函数的调用者,让调用者决定如何进一步处理错误。
use std::fs::File;use std::io;use std::io::Read;fn read_username_from_file() -> Result<String, io::Error> {
let mut s = String::new();
File::open("hello.txt")?.read_to_string(&mut s)?;
Ok(s)}fn main() {
let result = read_username_from_file();}
enum Option<T> {
Some(T),
None,}enum Result<T, E> {
Ok(T),
Err(E),}fn main() {}
再如下面的代码中x1方法只有在Point<i32>
中存在x1方法
struct Point<T> {
x: T,
y: T,}impl<T> Point<T> {
fn x(&self) -> &T {
&self.x }}impl Point<i32> {
fn x1(&self) -> &i32 {
&self.x }}fn main() {}
fn main(){
let s = String::from("Hello World");
take_ownership(s);
let x=5;
makes_copy(x);
println!("x:",x);}fn take_ownership(some_string:String){
println!("",some_string);}fn makes_copy(some_number:i32){
println!("",some_number);}
经过这一行take_ownership(s);
后变量s不能被使用,makes_copy(x);
后变量x依然可以被使用。
这是rust特有的所有权,和内存管理规则决定的: