Rust学习(7):函数

文章目录

  • 1、函数
    • 函数作为右值
    • 函数的类型
    • 函数体内可以定义函数
  • 2、发散函数
    • 什么叫做发散函数
    • 什么时候需要!【不懂】
    • 标准库中的!
  • 3、main函数
    • 函数的参数
    • 包含语句和表达式的函数体
    • 函数的返回值
      • 一个返回值
      • 多个返回值
    • 命令行传递参数
  • 4、const修饰的函数

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]
}

你可能感兴趣的:(#,rust)