Rust 学习笔记 - 函数详解

本文介绍了Rust编程语言中的函数定义、参数、返回值、参数可变性、私有性、可变参数和模式匹配的概念,以及与其它语言的区别和注意事项。后续将深入探讨所有权和借用等核心概念。
摘要由CSDN通过智能技术生成

前言

任何一门编程语言几乎都脱离不了:变量、基本类型、函数、注释、循环、条件判断,这是一门编程语言的语法基础,只有当掌握这些基础语法及概念才能更好的学习 Rust。

函数

在 Rust 中,函数是基本的执行单元,本篇将介绍 Rust 中的函数,包括其定义、参数、返回值以及一些注意事项。

函数定义与调用

  • Rust 中的函数使用fn关键字定义,后跟函数名称和一对圆括号。
  • 在圆括号中,可以定义零个或多个参数,每个参数后面跟着一个冒号(:)和它的类型。
  • 函数体用大括号({})包围。
  • 如果函数需要返回值,必须声明返回类型,通过在参数列表后添加一个箭头(->)和返回类型来完成。
fn <方法名>(<参数名1>: <类型>, <参数名2>: <类型2>) -> <返回值类型> {
    // 函数体,如果有返回值,则使用return关键字,或者省略它,
    // 最后的表达式作为返回值(无分号)
}

示例: 函数 main 是程序的入口,它会调用 another_function

fn main() {
    println!("Hello, world!");
    another_function();
}

fn another_function() {
    println!("另一个函数.");
}

参数

函数可以接收零个或者接受多个参数,并为参数指定类型:

fn print_sum(a: i32, b: i32) {
    println!("和是: {}", a + b);
}

fn main() {
    print_sum(5, 6);
}

在 Rust 中,函数参数是不可变的,需要显式使用mut关键字标识:

fn change_value(x: i32) {
    // 此时 x 会报错,因为 x 没有声明是可变的
    // error[E0384]: cannot assign to immutable argument `x`
    x += 1; 
    println!("x in function: {}", x);
}

fn main() {
    let mut x = 5;
    change_value(x);
    println!("x after function: {}", x);
}

使用mut关键字使参数可变:

fn change_value(mut x: i32) {
    // 这里 x 被成功修改
    x += 1;
    println!("x in function: {}", x);
}

fn main() {
    let mut x = 5;
    change_value(x);
    println!("x after function: {}", x);
}

返回值

在 Rust 函数中,返回值的类型紧跟在参数列表之后,并以 -> 开头,返回值通过在函数的最后一个表达式上省略分号来隐式返回的,这将变为函数的返回值。

注意: 最后一个表达式没有分号才作为返回值,如果有分号将作为一个表达式。

fn add(a: i32, b: i32) -> i32 {
    a + b // 注意这里没有分号,表示这是返回的值
}

在 Rust 中,返回值与最后一个表达式的值有关,并不需要显式的 return 关键字,如果确实需要提前返回,也可以像其他语言那样使用 return 关键字。

fn add(a: i32, b: i32) -> i32 {
	if a == 0 || b == 0 {
		return 0  // 通过 return 提前返回
	}
	a + b
}

私有性

在 Rust 中,默认情况下函数是私有的,只能在定义它们的模块内部访问。与其他语言不同的是,Rust 没有受保护(protected)、私有的(private) 关键字,只有 pub 关键字声明是公共的,当函数使用pub关键字后,才能使函数在其他模块中可见。

// 默认是私有的,只能在模块内访问
fn add(a: i32, b: i32) -> i32 {
	a + b
}

// 使用 pub 关键字声明公共的
pub fn add_two_num(a: i32, b: i32) -> i32 {
	a + b
}

可变参数

Rust 不支持直接的可变参数函数(Variadic Functions),但可以通过接受一个切片或者元组来间接实现。

数组可变参数示例

fn sum(slice: &[i32]) -> i32 {
    slice.iter().fold(0, |acc, &x| acc + x)
}

fn main() {
    let numbers = vec![1, 2, 3, 4, 5];
    let result = sum(&numbers);
    println!("The sum is {}", result);
}

在这个例子中,sum函数接受一个i32类型的切片作为参数,并使用迭代器的fold方法来计算总和。然后就可以通过一个向量调用这个函数,在这种情况下是numbers向量。将向量的借用&numbers传递给sum函数时,它将被自动借用为一个切片,这样函数就可以接受不同数量的参数。

元组可变参数示例

fn sum_tuple(args: (i32, i32, i32)) -> i32 {
    let (a, b, c) = args;
    a + b + c
}

fn main() {
    let result = sum_tuple((1, 2, 3));
    println!("The sum is {}", result);
}

在这个例子中,sum_tuple函数接受一个包含三个i32元素的元组。元组在参数列表中是固定大小的,但是可以通过创建不同大小的元组类型来模拟可变参数。但这种方法不如使用切片那样灵活,如果需要不同数量的参数,通常推荐使用切片。

模式匹配 / 参数解构

在 Rust 中,函数参数的行为就像let绑定一样,这意味着可以在函数定义中直接解构复合类型。例如,倘若你传递一个元组或结构体给函数,可以直接在参数列表中解构它们,从而得到它们的部分或全部内容。

这就像是在let语句中进行模式匹配,而函数参数就是所匹配的模式。这种特性在处理具有多个部分的数据类型时非常有用,我们无须先创建一个变量,然后再使用模式匹配来解构它,因为我们可以直接在函数的参数中完成这个步骤。

示例:

fn print_coordinates(&(x, y): &(i32, i32)) {
    println!("Current location: ({}, {})", x, y);
}

fn main() {
    let point = (3, 5);
    print_coordinates(&point);
}

在这个例子中,print_coordinates 函数接受一个引用到一个元组 (i32, i32) 的参数。参数 &(x, y) 是一个模式,它解构传入的元组,并允许我们在函数体内直接使用 xy。当我们调用 print_coordinates(&point) 时,point 元组被解构,元组中的值被分别绑定到 xy

同样的解构也可以被用在 let 绑定中,例如:

let (a, b) = (1, 2);

在这里,元组 (1, 2) 被解构,并且值 12 分别绑定到变量 ab

因此,Rust中的参数解构提供了一种非常强大和表达性的方式来处理输入参数,无需手动解构就可以直接取用复合型数据的一部分。

注意事项

rust 中的函数与其他语言有一些差异和需要注意的地方:

  • 函数和变量名采用 snake_case 的命名方式。
  • Rust 中的函数是表达式,这代表你可以在更大的表达式中嵌套使用它们。
  • Rust 不允许函数重载,即在同一作用域中不能有多个同名函数,即使参数类型不同也不行。
  • 没有默认参数值或参数名,不能像某些语言那样只提供某些参数。
  • 递归函数,即调用自身的函数,在 Rust 中是被允许的,但是需要注意栈溢出的风险。

结语

这是 Rust 基础语法的最后一篇,后面将开始讲解 Rust 所有权、借用等核心基础概念,但这块涉及比较多,加上新年开工比较忙,过段时间在更新相关内容。

  • 28
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值