我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Rust入门之函数和注释实例详解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Rust入门之函数和注释实例详解

写在前面

今天我们来学习 Rust 中的函数,最后会捎带介绍一下如何在 Rust 中写注释。也是比较轻量级的一节,大家快速过一下即可。

函数

函数本身是各个语言都支持的类型,我们此前已经多次使用 fn main() 这个函数来承载业务逻辑,fn 可以用来声明一个函数,而 main 函数跟其他语言一样,可以理解为程序启动的【起点】,一切逻辑从这里开始。

Rust 本身的命名规范是【snake case】,即下划线 + 小写,这个其实各个语言都有自己规范,分清楚环境即可。

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

这里的 another_function 就是个没有入参,没有出参的函数,命名遵循 snake case,很好理解。

Rust 中的函数跟其他语言是一样的,用 fn 来声明,后面加上函数名,小括号里面可以放入参,之后可以定义出参,最后用花括号来承载函数体。调用函数也不复杂,函数名后面跟上小括号+参数即可,注意 scope 就行,这里是因为我们的 another_function 就在当前包下,所以直接就那来调用。调用的时候要保证【函数所在的 scope 是对 caller 可见】的即可。

我们在 rust-learn 项目下通过 cargo new functions 新建一个项目,试一下上面的代码:

$ cargo run
===============================
   Compiling functions v0.1.0 (/Users/ag9920/go/class="lazy" data-src/github.com/ag9920/rust-learn/functions)
    Finished dev [unoptimized + debuginfo] target(s) in 1.76s
     Running `target/debug/functions`
Hello, world!
Another function.

另外需要强调一点,Rust 文件内函数定义并不要求顺序,只要定义在 scope 内就能解析,比如 main 函数先于 another_function 定义是没问题的。

参数

还是基于我们此前的 another_function,我们尝试加一下入参,看看应该怎么做:

fn main() {
    another_function(5);
}
fn another_function(x: i32) {
    println!("The value of x is: {x}");
}

执行过后,结果如下:

$ cargo run
===============================
   Compiling functions v0.1.0 (/Users/ag9920/go/class="lazy" data-src/github.com/ag9920/rust-learn/functions)
    Finished dev [unoptimized + debuginfo] target(s) in 0.62s
     Running `target/debug/functions`
The value of x is: 5

此时 another_function 增加了一个参数 x,我们声明其类型为 i32。在 main 函数中调用的时候,传入我们的参数 5,最后被打印出来。

可能有的地方会特意提一下这两个概念:

  • 形参:是在定义函数时使用的参数,目的是用来接收调用该函数时传进来的实际参数,即 parameter;
  • 实参:是在调用时传递给函数的参数,即 arguments。

但通常说起来的时候我们不太区分,对我们来说统一叫【参数】即可。

上面示例中,我们定义入参是这样的:fn another_function(x: i32)

这里【冒号 + 空格 + 类型】的写法我们已经见过很多次了,那能不能不带类型呢?我直接写个 fn another_function(x),具体格式留给编译器来推断 ok 不?

在 Rust 中这件事是不 ok的,按照规范,对于每个入参你都必须清晰地指明【类型】,这样编译器也省事,报错时也能更精准给出相关判断。如果我们需要多个入参,用【逗号】分隔即可:

fn main() {
    print_labeled_measurement(5, 'h');
}
fn print_labeled_measurement(value: i32, unit_label: char) {
    println!("The measurement is: {value}{unit_label}");
}

执行结果如下:

$ cargo run
========================
  Compiling functions v0.1.0 (/Users/ag9920/go/class="lazy" data-src/github.com/ag9920/rust-learn/functions)
    Finished dev [unoptimized + debuginfo] target(s) in 0.87s
     Running `target/debug/functions`
The measurement is: 5h

语句和表达式

Rust 本身是一个基于表达式的语言,所以这两个概念我们先区分一下,语句(statements),表达式(expressions)是什么区别?

Statements are instructions that perform some action and do not return a value. Expressions evaluate to a resulting value.

简单说,就是看有没有【返回值】,无返回值的是语句,有返回值的是表达式,表达式可以是一个语句的组成部分。

举个例子:let y = 6; 这就是一个【语句】,而 6 就是一个【表达式】,在 Rust 中你是不能做 let x = (let y = 6); 这样的操作的,因为括号里面的部分是个语句,语句没有返回值,那么该拿什么给 x 赋值呢?

所以,不像其他语言,可能允许类似 x = y = 6,这样让 x 和 y 都赋值了 6。Rust 是不允许这样的。

fn main() {
    let y = {
        let x = 3;
        x + 1
    };
    println!("The value of y is: {y}");
}

比如上面这个案例,在花括号这个 scope 中,我们定义了 x 变量,将其赋值为 3,然后将 x+1 这个表达式返回,所以 y 被赋值为 4。

花括号里面的部分就是一个表达式,返回了 4 。注意 x + 1 的结尾没有分号,这也是表达式的特征。这里千万不能加分号,要想清楚。如果你想用一个表达式返回,就不加分号。加了之后变成了语句,但也不会返回什么东西。

Rust 函数体则是由一系列【语句】+ 默认可选的一个【表达式】组成。为什么是可选的?因为类似我们前面的函数,没有返回值,不需要最后的这个【表达式】。

返回值

Rust 是不支持命名返回值的(这一点跟 Golang 有所不同),函数定义出参的部分需要用【箭头符号】显式地声明。

不像很多函数要求显式的 return 返回值,Rust 默认会返回最后的表达式的值。当然我们如果想 early return 也是 ok的,但大多数函数不会写 return 这个关键字,而是隐式地返回最后一个表达式。我们来看一个例子:

fn five() -> i32 {
    5
}
fn main() {
    let x = five();
    println!("The value of x is: {x}");
}

这里的 five 函数非常简单,只有一个 5 作为表达式返回,不需要 return。

这是完全合法的 Rust 函数,出参只有一个 i32。我们加上入参,再看一个例子:

fn main() {
    let x = plus_one(5);
    println!("The value of x is: {x}");
}
fn plus_one(x: i32) -> i32 {
    x + 1
}

此时我们有一个 i32 入参,也有一个 i32 出参,函数体是一个简单的表达式 x + 1。运行上面代码打印的结果是 The value of x is: 6,符合预期。

我们试试给 x + 1 后面加上个分号看看:

fn main() {
    let x = plus_one(5);
    println!("The value of x is: {x}");
}
fn plus_one(x: i32) -> i32 {
    x + 1;
}

此时运行结果果然报错(这个不是运行时报错,是编译阶段识别的)

$ cargo run
====================
   Compiling functions v0.1.0 (/Users/ag9920/go/class="lazy" data-src/github.com/ag9920/rust-learn/functions)
error[E0308]: mismatched types
 --> class="lazy" data-src/main.rs:7:24
  |
7 | fn plus_one(x: i32) -> i32 {
  |    --------            ^^^ expected `i32`, found `()`
  |    |
  |    implicitly returns `()` as its body has no tail or `return` expression
8 |     x + 1;
  |          - help: remove this semicolon
For more information about this error, try `rustc --explain E0308`.
error: could not compile `functions` due to previous error

问题在于,plus_one 说了会有返回值 i32,但到最后也没发现【表达式】,此时 Rust 默认会返回 () 一个空的 tuple(我们上一节讲过,这个叫 unit),所以报错叫做【 mismatched types】,而不是类似【no return value】,这里是不是就理解了?

没有返回值的函数,本质上是返回了一个 unit:

// Functions that "don't" return a value, actually return the unit type `()`
fn fizzbuzz(n: u32) -> () {
    if is_divisible_by(n, 15) {
        println!("fizzbuzz");
    } else if is_divisible_by(n, 3) {
        println!("fizz");
    } else if is_divisible_by(n, 5) {
        println!("buzz");
    } else {
        println!("{}", n);
    }
}

问题又来了,那 Rust 能不能支持多个出参呢?类似 Golang 中的:

func addsub(x, y int) (int, int) {
    return x + y, x - y
}

其实 Rust 对这个事情的解决方案就是我们已经见过多次的 tuple:

fn addsub(x: isize, y: isize) -> (isize, isize) {
    (x + y, x - y)
}
fn my_func() -> (u8, bool) {
    (1, true)
}

圆括号千万不能少,记住我们 return 的是个 tuple,不是多个单独的值。

这里有一个可运行的 online 示例,大家可以复习一下 tuple,结合多个返回值体会一下:

fn swap(x: i32, y: i32) -> (i32, i32) {
    return (y, x);
}
fn main() {
    // return a tuple of return values
    let result = swap(123, 321);
    println!("{} {}", result.0, result.1);
    // destructure the tuple into two variables names
    let (a, b) = swap(result.0, result.1);
    println!("{} {}", a, b);
}

注释

注释其实比较简单,我们快速提一下。

Rust 的行注释就是常见的 // 双斜杠,如果一行放不下,需要多行的话,也需要在每一行前面加.

fn main() {
    // I'm feeling lucky today
    let lucky_number = 7;
}

文档注释有些许的区别,这里需要用 /// 三斜杠,这样能够辅助生成 HTML 文档。

/// Adds one to the number given.
///
/// # Examples
///
/// ```
/// let arg = 5;
/// let answer = my_crate::add_one(arg);
///
/// assert_eq!(6, answer);
/// ```
pub fn add_one(x: i32) -> i32 {
    x + 1
}

以上就是Rust 入门之函数和注释实例详解的详细内容,更多关于Rust 函数注释的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Rust入门之函数和注释实例详解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Python入门之三角函数sin()函数实例详解

描述 sin()返回的x弧度的正弦值。 语法 以下是sin()方法的语法:importmath math.sin(x)注意:sin()是不能直接访问的,需要导入math模块,然后通过math静态对象调用该方法。 参数 x--一个数值。 返
2022-06-04

Python入门之三角函数tan()函数实例详解

描述tan() 返回x弧度的正弦值。语法以下是 tan() 方法的语法:import math math.tan(x)注意:tan()是不能直接访问的,需要导入 math 模块,然后通过 math 静态对象调用该方法。参数x -- 一个数值
2022-06-04

Python入门之三角函数atan2()函数详解

描述atan2() 返回给定的 X 及 Y 坐标值的反正切值。语法以下是 atan2() 方法的语法:import math math.atan2(y, x)注意:atan2()是不能直接访问的,需要导入 math 模块,然后通过 math
2022-06-04

Java注释和关键字实例详解

注释是对程序语言的说明,有助于开发者和用户之间的交流,方便理解程序,注释不是编程语句,因此被编译器忽略,下面这篇文章主要给大家介绍了关于Java注释和关键字的相关资料,需要的朋友可以参考下
2023-01-15

MySQL数据库入门之多实例配置方法详解

本文实例讲述了MySQL数据库入门之多实例配置方法。分享给大家供大家参考,具体如下: 前面介绍了相关的基础命令操作:MySQL数据库基础篇之入门基础命令 所有的操作都是基于单实例的,mysql多实例在实际生产环境也是非常实用的,因为必须要掌
2022-05-31

python strip() 函数和 split() 函数的详解及实例

python strip() 函数和 split() 函数的详解及实例 一直以来都分不清楚strip和split的功能,实际上strip是删除的意思;而split则是分割的意思。因此也表示了这两个功能是完全不一样的,strip可以删除字符串
2022-06-04

C++入门教程之内联函数与extern "C"详解

C++中的内联函数与静态函数静态函数静态函数的定义静态函数又称为内部函数,下面这篇文章主要给大家介绍了关于C++入门教程之内联函数与extern "C"的相关资料,需要的朋友可以参考下
2023-01-10

实例详解JavaScript构造函数和原型

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于构造函数和原型的相关问题,以及prototype相关内容,下面一起来看一下,希望对大家有帮助。
2022-11-24

PHP数组用法详解:快速入门与实例分析

PHP 数组是一种非常强大且灵活的数据结构,可以存储多个值并按照索引或键进行访问。在 PHP 中,数组的使用非常普遍,因此掌握数组的用法是非常重要的。本文将从快速入门开始,介绍 PHP 数组的基本概念以及常见操作,并通过实例分析来帮助读者深
PHP数组用法详解:快速入门与实例分析
2024-03-14

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录