1. 字符串
String、&str、&String、Box<str> 或 Box<&str>这些能区分吗?
1.1 String
String:这是一个动态的,可增长的字符串类型。它被分配在堆上并且可以修改。常用于需要创建或修改字符串的场合
let mut s = String::new();
s.push_str("apache mxsm");
println!("{}", s);
1.2 &str
&str 是一个不可变的字符串 slice,它存储在栈上。常用于固定的、不需要修改的字符串。
let s: &str = "apache mxsm";
let ss: &'static str = "apache mxsm";
const SSS: &str = "apache mxsm";
1.3 &String
&String:这是一个指向 String 的引用,常用于函数参数,以便可以接受 String 类型也可以接受 &str 类型。
fn main() {
mxsm(&"apache mxsm".to_string(),"apache")
}
fn mxsm(name:&String, address:&str){
}
1.4 Box<str>和Box<&str>
Box<str>和Box<&str>不常用
let s: Box<str> = Box::from("apache mxsm");
let ss: Box<&str> = Box::from("apache mxsm");
2.fn,Fn,FnMut,FnOnce
首先我们了解一下Rust的闭包:Rust 的 闭包(closures)是可以保存在一个变量中或作为参数传递给其他函数的匿名函数。
- 将函数或者说代码和其环境一起存储的一种数据结构
- 闭包引用的上下文中的自由变量,会被捕获到闭包的结构中,成为闭包类型的一部分
2.1 fn函数指针
fn 被称为 函数指针(function pointer)。通过函数指针允许我们使用函数作为另一个函数的参数。
fn add_one(x: i32) -> i32 {
x + 1
}
fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
f(arg) + f(arg)
}
fn main() {
let answer = do_twice(add_one, 5);
println!("The answer is: {}", answer);
}
fn不要与闭包 trait 的
Fn相混淆。
2.2 FnOnce
FnOnce 适用于能被调用一次的闭包,所有闭包都至少实现了这个 trait,因为所有闭包都能被调用。一个会将捕获的值移出闭包体的闭包只实现 FnOnce trait,这是因为它只能被调用一次。 看一下FnOnce的源码:
pub trait FnOnce<Args: Tuple> {
#[lang = "fn_once_output"]
#[stable(feature = "fn_once_output", since = "1.12.0")]
type Output;
#[unstable(feature = "fn_traits", issue = "29625")]
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}
2.3 FnMut
FnMut适用于不会将捕获的值移出闭包体的闭包,但它可能会修改被捕获的值。这类闭包可以被调用多次。
pub trait FnMut<Args: Tuple>: FnOnce<Args> {
/// Performs the call operation.
#[unstable(feature = "fn_traits", issue = "29625")]
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
}
从源码可以看出来FnMut继承了FnOnce
2.4 Fn
Fn 适用于既不将被捕获的值移出闭包体也不修改被捕获的值的闭包,当然也包括不从环境中捕获值的闭包。这类闭包可以被调用多次而不改变它们的环境,这在会多次并发调用闭包的场景中十分重要。
pub trait Fn<Args: Tuple>: FnMut<Args> {
/// Performs the call operation.
#[unstable(feature = "fn_traits", issue = "29625")]
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
}
通过上述的源码可以发现:
- FnOnce参数使用的 self ,而 FnMut 使用的是 &mut self , Fn使用的是**&sel**f 这也就说明了上面说的三者的捕获值的特点
- 三者之间是存在继承关系
3. 表达式是否带分号(;)
首先我们需要有一个最基本的认识: Rust是基于表达式的语言,几乎所有代码都可以看作是表达式。 我们看一下下面的代码
fn main() {
4+5;
}
fn main() {
4+5 // 编译不正确,因为main的返回值为()
}
上面包含了两段代码,代码也仅仅是有无**分号(;)**的区别,为什么第一段代码正常,第二段代码就报错了。 这里就和上面说的Rust是基于表达式的语言。表达式处理完成后就会有一个返回值,而main没有返回值或者说返回值为()。但是表达式返回值为9i32的类型所以报错。而第一段代码也看看成
fn main() {
4+5;
()
}
我是蚂蚁背大象,文章对你有帮助给项目点个❤关注我GitHub:mxsm,文章有不正确的地方请您斧正,创建ISSUE提交PR~谢谢! Emal:mxsm@apache.com