1、函数
函数作为右值
和C++不同的是,函数可以被当成头等公民被复制到一个值中,这个值可以像返回一样被调用
fn main() {
let tup = (1, 2);
let fun = add1; //fn类型:fn((i32, i32))->i32
let x = fun(tup); // 局部变量func 可以被当成普通函数一样被调用
println!("x = {}", x);
}
fn add1(t:(i32, i32))->i32{
return t.0 + t.1; //语句;并不会返回值,因此return显示指定
}
函数的类型
rust中,每个函数都有自己单独的类型
- 虽然add1和add3处理函数名字不一样,其他都一样,但是它们仍是是不同类型
fn main() {
let mut fun = add1; //fn类型:fn((i32, i32))->i32
fun = add3; //error[E0308]: mismatched types
}
fn add1(t:(i32, i32))->i32{
return t.0 + t.1;
}
fn add3(t:(i32, i32))->i32{
return t.0 + t.1;
}
- 修复上面的错误
方法1:使用显示类型标记【去掉参数就是类型】
fn main() {
let tup = (1, 2);
let mut fun:fn((i32, i32))->i32 = add1; //fn类型
println!("x = {}", fun(tup));
fun = add3;
println!("x = {}", fun(tup));
fun = add2;
println!("x = {}", fun(tup));
}
fn add1(t:(i32, i32))->i32{
return t.0 + t.1;
}
fn add3(t:(i32, i32))->i32{
return t.0 + t.1;
}
fn add2((x, y):(i32, i32))->i32{
x + y
}
方法2:使用as类型转换【去掉参数就是类型】
fn main() {
let tup = (1, 2);
let mut fun = add1 as fn((i32, i32))->i32;
println!("x = {}", fun(tup));
fun = add3;
println!("x = {}", fun(tup));
fun = add2;
println!("x = {}", fun(tup));
}
fn add1(t:(i32, i32))->i32{
return t.0 + t.1;
}
fn add3(t:(i32, i32))->i32{
return t.0 + t.1;
}
fn add2((x, y):(i32, i32))->i32{
x + y
}
备注:上面的这两种方法都不能修改参数类型或者返回值类型不同的情况,比如
fn main() {
let tup = (1, 2);
let mut fun = add1 as fn((i32, i32))->i32;
fun = add2; //error[E0308]: mismatched types
}
fn add1(t:(i32, i32))->i32{
return t.0 + t.1;
}
fn add2(x:i32)->i32{
x
}
函数体内可以定义函数
在Rust的函数体内运行定义其他item,比如静态变量,常量,函数,trait,类型,模块等等
fn main() {
static INNER_STATIC:i64 = 42;
//函数体内定义函数
fn internal_incre(x:i64)->i64{
x+1
}
struct InnerStruct(i64);
impl InnerStruct{
fn incre(&mut self){
self.0 = internal_incre(self.0)
}
}
let mut t = InnerStruct(INNER_STATIC);
t.incre();
println!("{}", t.0)
}
当一些item仅在此函数体内有用时,可以把它们直接定义在函数体内,以免污染外部的命名空间。
2、发散函数
什么叫做发散函数
当一个函数不能正常返回时,可以定义它的返回类型是!,这种函数叫做发散函数
fn diverge() ->!{
panic!("the function never return!")
}
fn main() {
let x:i32 = diverge();
let y:String = diverge();
}
!又叫做发散类型,发散类型可以转换为任何类型
什么时候需要!【不懂】
let p = if x > 0{
panic!("error")
}else{
100;
};
if-else每条分支的类型必须一致
标准库中的!
在Rust中,有以下这些情况永远不会返回,它们的类型就是!。
- panic!以及基于它实现的各种函数/宏,比如unimplemented!、unreachable!;
- 死循环loop{};
- 进程退出函数std::process::exit以及类似的libc中的exec一类函数。
3、main函数
函数的参数
fn main() {
test(11, 11.1);
}
fn test(x:i32, y:f32){
println!("hello world!, x = {}, y = {}", x, y);
}
1、参数是特殊变量,是函数签名的一部分
2、在函数签名中,必须 声明每个参数的类型
3、当一个函数有多个参数时,使用逗号分隔
4、println!中的!表示这是一个宏而不是一个函数,Rust中的宏可以理解为一种安全版的编译器语法扩展。这里之所以适用宏而不是函数,是因为标准输出宏可以完成编译器格式检查,更加安全
包含语句和表达式的函数体
函数体由一系列语句和一个可选的结尾表达式构成
- 语句是指定一些操作但是不返回值的指令,没有返回值,因此语句的类型永远是()
- 表达式计算并产生一个值,因此表达式一定有类型。
fn main() {
let x = 3; //语句:没有返回值,因此不能用来赋值
//let y = (let x = 3); //error: let x = 3语句并不返回值,所以没有可以绑定到y上的值
//let y = (x = 3); //error
let y = x + 1;
let z = {
let x = 3;
x + 1
};
print!("{},{}", y, z);
// let z = {
// let x = 3;
// return x + 1; //error[E0308]: mismatched types
// };
}
1、表达式的结尾没有分号。如果在表达式的结尾加上分号,它就变成了语句,而语句不会返回值
2、Rust表达式分为"左值"和”右值“两类。所谓左值,就是这个表达式可以表达一个内存地址,因此它们可以放到赋值运算符左边使用。其他的都是右值
函数的返回值
一个返回值
fn main() {
let tup = (1, 2);
let x = add1(tup);
println!("x = {}", x);
let x = add2(tup);
println!("x = {}", x);
}
fn add1(t:(i32, i32))->i32{
return t.0 + t.1; //语句;并不会返回值,因此return显示指定
}
fn add2((x, y):(i32, i32))->i32{
x + y //函数的返回值等同于函数体最后一个表达式的值
}
1、在 Rust 中,函数的返回值等同于函数体最后一个表达式的值。使用 return 关键字和指定值,可从函数中提前返回;但大部分函数隐式的返回最后的表达式
多个返回值
可以通过元组来返回多个值
fn main() {
let (x, y) = test1(11);
println!("x = {}, y = {}", x, y);
}
fn test1(x:i32)->(i32, i32){
return (x + 1, x + 2); //语句;并不会返回值,因此return显示指定
}
可以使用结构体来返回多个值
命令行传递参数
标准库中的 std::env::args()可以获取命令行传递的参数
fn main() {
for arg in std::env::args() {
println!("Arg: {}", arg);
}
std::process::exit(0)
}
- rustc main.rs
- ./main -opt1 opt2 – opt3
如何获取环境变量
。。。
4、const修饰的函数
函数可以用const关键字修饰,这样的函数在编译阶段就被编译器执行,返回值也被视为编译起常量。
const fn cube(num:usize)->usize{
num * num * num
}
fn main() {
const DIM:usize = cube(2); //常量不能类型推导, 常量的值必须是编译器间就能确定的常量
const ARR:[i32;DIM] = [0; DIM];
println!("{:?}", ARR) //[0, 0, 0, 0, 0, 0, 0, 0]
}