100 Exercises To Learn Rust 挑战!构文・整数・变量

news2024/11/27 22:44:17

前一篇文章

【0】准备
【1】构文・整数・变量 ← 本次
全部文章列表
《100 Exercise To Learn Rust》第2回,也就是实际演习的第1回!从这次开始,我们会适度减少前置说明,直接进入问题的解决!

本次的相关页面

  • 1.1. Syntax
  • 2.1. Integers
  • 2.2. Variables

[01_intro/01_syntax] 基本文法

  • 1.1. Syntax

问题如下: 

// TODO: fix the function signature below to make the tests pass.
//  Make sure to read the compiler error message—the Rust compiler is your pair programming
//  partner in this course and it'll often guide you in the right direction!
//
// The input parameters should have the same type of the return type.
fn compute(a, b) -> u32 {
    // Don't touch the function body.
    a + b * 2
}

#[cfg(test)]
mod tests {
    use crate::compute;

    #[test]
    fn case() {
        assert_eq!(compute(1, 2), 5);
    }
}

“在Rust中,编译器是你最好的朋友,所以一定要认真听取编译器君的建议!” 大概是这个意思(非常意译)。实际上确实如此,所以这次我们首先来看一下编译错误。

$ wr
 

Running tests...

        ✅ (01) intro - (00) welcome (Skipped)
        ❌ (01) intro - (01) syntax

        Meditate on your approach and return. Mountains are merely mountains.



error: expected one of `:`, `@`, or `|`, found `,`
 --> exercises/01_intro/01_syntax/src/lib.rs:6:13
  |
6 | fn compute(a, b) -> u32 {
  |             ^ expected one of `:`, `@`, or `|`
  |
  = note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
help: if this is a `self` type, give it a parameter name
  |
6 | fn compute(self: a, b) -> u32 {
  |            +++++
help: if this is a parameter name, give it a type
  |
6 | fn compute(a: TypeName, b) -> u32 {
  |             ++++++++++
help: if this is a type, explicitly ignore the parameter name
  |
6 | fn compute(_: a, b) -> u32 {
  |            ++

error: expected one of `:`, `@`, or `|`, found `)`
 --> exercises/01_intro/01_syntax/src/lib.rs:6:16
  |
6 | fn compute(a, b) -> u32 {
  |                ^ expected one of `:`, `@`, or `|`
  |
  = note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
help: if this is a parameter name, give it a type
  |
6 | fn compute(a, b: TypeName) -> u32 {
  |                ++++++++++
help: if this is a type, explicitly ignore the parameter name
  |
6 | fn compute(a, _: b) -> u32 {
  |               ++

error: could not compile `syntax` (lib) due to 2 previous errors
error: could not compile `syntax` (lib test) due to 2 previous errors

一开始可能会被长长的错误信息压倒,但这些错误并不是随便给出的,而是大多提供了便于查找的错误信息。所以如果认真阅读,能学到很多东西。

虽然显示了两个错误,但它们几乎是相同的。

error: expected one of `:`, `@`, or `|`, found `,`
 --> exercises/01_intro/01_syntax/src/lib.rs:6:13
  |
6 | fn compute(a, b) -> u32 {
  |             ^ expected one of `:`, `@`, or `|`
  |
  = note: anonymous parameters are removed in the 2018 edition (see RFC 1685)

由于是语法问题,因此出现了与语法相关的错误。就像在做“理所当然体操”一样。

在错误信息下面有三条帮助提示,它们似乎根据我们的意图进行了分类。

  • 如果是 self 类型,请加上 self
  • self 是定义方法时的语法糖,这次不适用。
  • 如果是指参数(参数名),请写上类型。
  • 如果是指类型名,请加上参数名。 (虽然并没有这样直接写,而是提示使用 _ 来表示未使用的参数。)

这次的错误可能与第二点或第三点有关,即“应该同时明确写出参数名和类型,但只写了其中之一”。

在绑定变量时可以省略类型名(后面会详细说明,但必须静态确定),不过由于Rust是静态类型语言,所以在函数签名中特别需要明确指定类型。

解说

我们回到问题所在的部分。ab 是以小写字母开头的标识符。在Rust中,变量名通常采用蛇形命名法(snake_case),而类型名和特征名则采用帕斯卡命名法(PascalCase),因此这些标识符应该是变量名。

因此,我们需要为它们添加类型名。由于Rust不会进行隐式类型转换,为了最小化修改(也就是遵循“不要触碰函数体”的原则),将它们设为 u32 类型似乎是最合适的选择。

- fn compute(a, b) -> u32 {

+ fn compute(a: u32, b: u32) -> u32 {

    // Don't touch the function body.
    a + b * 2
}

成功通过了!让我们继续下一个问题。

(按顺序的话应该是 02_basic_calculator/00_intro,不过看起来只是做个标题调用,所以我们跳过它。后面的章节似乎也是类似的情况。)

[02_basic_calculator/01_integers] 整数型

  • 2.1. Integers

问题如下: 

fn compute(a: u32, b: u32) -> u32 {
    // TODO: change the line below to fix the compiler error and make the tests pass.
    a + b * 4u8
}

#[cfg(test)]
mod tests {
    use crate::compute;

    #[test]
    fn case() {
        assert_eq!(compute(1, 2), 9);
    }
}

虽然与刚才的问题类似,但这次更强调了 没有隐式类型转换 这一点。

解说

4u8 是一个表示 u8 类型的数字 4 的字面量。由于不会进行隐式类型转换,如果一开始就将其设定为 u32 类型的 4,效果会更好。

fn compute(a: u32, b: u32) -> u32 {
    // TODO: change the line below to fix the compiler error and make the tests pass.

-    a + b * 4u8

+    a + b * 4u32

}

u32u8 中的 u 代表无符号整数(unsigned integer),i32i8 中的 i 代表整数(integer)。在Rust中,为了防止出现错误,通常在不需要表示负数时会使用无符号整数。

虽然有很多关于二进制补码和字节宽度的讨论,但最终我们会关心“最大值和最小值到底是多少?” 这些值可以通过 MINMAX 方法来确认。

  • i32::MIN ( = -2147483648 )
  • u32::MAX ( = 4294967295 )

此外,虽然在本节中尚未提及,但 usize 可能是你最常见到的整数类型。之所以如此,是因为这个整数类型非常特殊,它可以用于数组的索引。换句话说,usize 是一种接近地址值的类型。在32位操作系统中,它是32位宽;在64位操作系统中,它是64位宽,因此被赋予了“size”这个名称。

[02_basic_calculator/02_variables] 变量

  • 2.2. Variables

问题如下: 

pub fn speed(start: u32, end: u32, time_elapsed: u32) -> u32 {
    // TODO: define a variable named `distance` with the right value to get tests to pass
    //  Do you need to annotate the type of `distance`? Why or why not?

    // Don't change the line below
    distance / time_elapsed
}

#[cfg(test)]
mod tests {
    use crate::speed;

    #[test]
    fn case1() {
        assert_eq!(speed(0, 10, 10), 1);
    }

    #[test]
    fn case2() {
        assert_eq!(speed(10, 30, 10), 2);
    }

    #[test]
    fn case3() {
        assert_eq!(speed(10, 31, 10), 2);
    }
}

提示内容是:distance 变量尚未定义,请定义它。

解说

通过用终点坐标减去起点坐标可以得到距离,因此可以将其绑定为 distance 变量。

pub fn speed(start: u32, end: u32, time_elapsed: u32) -> u32 {
    // TODO: define a variable named `distance` with the right value to get tests to pass
    //  Do you need to annotate the type of `distance`? Why or why not?

+    let distance = end - start;


    // Don't change the line below
    distance / time_elapsed
}

从练习的意图来看,似乎是想引导你思考:“既然是强类型静态语言,为什么不需要为 distance 指定类型(比如写作 let distance: u32 = ...)呢?” 其实,Rust具有相当强大的类型推断机制,如果可以从相关的运算等推断出类型,就不会出现错误。

另外,VSCode 的 rust-analyzer插件还具有一个功能,即“当类型可以被推断时,会以灰色显示该类型”。

“Rust一开始有点难上手,但自从 rust-analyzer 能帮忙添加类型注释后,就变得容易多了,” 这是我朋友说的。而实际上,这个功能确实使得Rust既易于编写又保持对类型的严格要求,同时也让 VSCode + rust-analyzer 成为了最好的Rust编辑器组合。

总结

最后一个问题很有特点,通过这三道题我们了解到:

  • 函数的签名必须由人手动指定。
  • 作为一种强类型静态语言,显然不允许隐式类型转换。
  • 由于类型推断机制,变量的类型注释在一定程度上可以省略。

这表明,Rust并不是要求在所有地方都必须进行类型注释,而是在需要的地方,比如函数签名,才需要人手动进行类型注释。正因为这一特点,笔者认为,Rust的类型系统相比其他语言更容易上手。

下一篇文章: 【2】if・panic・练习

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2034958.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VUE3请求意外报跨越错误或者500错误问题

1.有可能是请求传参和传参类型写错了 首先要确保该请求接口是支持跨域的(不支持叫后端改) access-control-allow-headers:Content-Type, Accept, Access-Control-Allow-Origin, api_key, Authorization access-control-allow-methods:GET, POST, OPTIO…

【docker】dockerfile部署lnmp、docker compose初步

1、dockerfile部署lnmp mkdir /opt/lnmp cd /opt/lnmp mkdir nginx mysql php docker network create --subnet20.0.0.0/24 lnmp-net将wordpress文件夹拷贝到nginx、php文件夹 /opt/nginx/Dockerfile: # 使用官方的nginx镜像作为基础镜像 FROM nginx:latest# 复制默认配置文件…

【QGroundControl二次开发】十. QT添加GStreamer视频播放同时保存

上一章介绍使用QT播放GStreamer视频流 【QGroundControl二次开发】八. QT实现播放gstreamer视频。 这章介绍如何在原有基础上保存为视频,同时保存为一个个规定大小的小视频。 一. 思想 之前的文章展示了如何在QT中播放GST视频流,这章在原有的基础上增加…

vue-cli(二)

箭头函数 一般的函数: 这里window是用来调用函数的 function fun(){console.log(this) } window.fun(); 箭头函数: 1、如果只有一个参数,形参的小括号可以省略 2、如果只有一条语句,{}可以省略 完整的写法 let fun2 a>…

前缀和优化DP

LeetCode3251 单调数组对数目 本题的子问题是下标 0 到 i 中的单调数组对的个数&#xff0c;且 arr1​[i]j&#xff0c;将其记作 f[i][j]。 class Solution { public:int countOfPairs(vector<int>& nums) {const int mod1e97;int nnums.size();int mnums[0];for(in…

C++(STL)的List解读

目录 list简介 list的几个特性 接口函数 1.默认成员函数 2.迭代器相关函数 3.容量相关的函数 4.成员访问相关的函数 5.modify系列 6.operation系列 7.重载在全局的函数 list简介 Lists are sequence containers that allow constant time insert and erase operation…

【Linux】阻塞信号|信号原理|深入理解捕获信号|内核态|用户态|sigaction|可重入函数|volatile|SIGCHILD|万字详解

目录 ​编辑 一&#xff0c;常见的信号术语 二&#xff0c;信号在内核中的表示 信号标志位 Pending表 Block表 handler表 POSIX.1标准 三&#xff0c;sigset_t 信号集操作函数 sigemptyset sigfillset sigaddset sigdelset sigismember sigprocmask sig…

ISP 代理与住宅代理 – 终极指南

模拟自然的、类似人类的流量可能很麻烦&#xff0c;但对于某些任务&#xff08;如帐户管理或网络自动化&#xff09;&#xff0c;没有它就无法完成。ISP 和住宅代理都可以提供帮助&#xff0c;但您不能盲目购买和部署它们。您需要了解它们的优势&#xff0c;理解它们的弱点&…

买的谷歌游戏账号被删了?如果是企业账号找回来的可能性很小。一个识别谷歌企业号的简单方法

这段时间有几个朋友找到我说&#xff0c;自己买的谷歌账号登录不了&#xff0c;有的是直接提示被删除&#xff0c;问能否恢复。 我了解了一下&#xff0c;发现他们的账号都是购买的企业账号。这种企业账号一旦被管理员删除了是无法恢复的。 特此记录下来&#xff0c;提醒各位…

8月13日笔记

msf补充 使用方法&#xff1a; 进入框架&#xff1a;msfconsole 使用search命令查找相关漏洞&#xff1a;search ms14-058 使用info查看模块信息&#xff1a;info 我们也可以将攻击代码写configure.rc&#xff08;只要是以 .rc 结尾的文件&#xff09;配置文件中&#xff0c;然…

【数学建模】介绍论文书写格式

&#x1f308;个人主页&#xff1a;Yui_ &#x1f308;Linux专栏&#xff1a;Linux &#x1f308;C语言笔记专栏&#xff1a;C语言笔记 &#x1f308;数据结构专栏&#xff1a;数据结构 文章目录 1.论文整体排版2. 标题书写3.摘要书写4.参考文献5.公式编辑5.1 常用公式编辑方法…

JavaScript 逆向技巧总结

本节属于知识总结&#xff0c;只是对思路的梳理&#xff0c;不对具体内容进行展开 JS 逆向可以分为三大部分&#xff1a; 寻找入口&#xff0c; 调试分析&#xff0c; 模拟执行 寻找入口&#xff1a; 这是非常关键的一步&#xff0c;逆向在大部分情况下就是找一些加密参数到底…

Linux磁盘管理与文件系统(二):实用工具和命令、fdisk分区示例

文章目录 4、查看或管理磁盘分区-fdisk格式选项示例 4、示例&#xff1a;使用 fdisk 命令创建分区需求操作步骤 5、创建文件系统-mkfs格式常用选项示例创建其他类型的文件系统 6、创建文件系统-mkswap格式常用选项示例拓展&#xff1a;关闭和启用交换分区拓展&#xff1a;swap分…

搬瓦工澳大利亚AS9929 VPS测评

搬瓦工澳大利亚vps怎么样&#xff1f;搬瓦工澳大利亚悉尼数据中心在运作CUII/AS9929线路的VPS&#xff0c;底层为KVM虚拟&#xff0c;纯SSD阵列&#xff0c;1Gbps带宽... 目前看到的是CPU主频是2.4GHz&#xff0c;接入XTOM网络&#xff0c;IP归属澳大利亚&#xff0c;当前大致I…

window好用的批量远程桌面连接工具

下载 安装 Remote Desktop Connection Manager 添加server

AlexNet模型搭建(三部曲_2)

文章目录 1模型介绍2 模型搭建3 模型训练4 模型预测 猫狗二分类&#xff0c;模型简单&#xff0c;训练精度并不高。数据集下载&#xff1a;<https://aistudio.baidu.com/datasetdetail/26884> 百度飞浆上找的大小只有60多M 1模型介绍 AlexNet是一个卷积神经网络的名字&a…

Linux命令(基础面试可用,都是自己觉得平时使用多的)

1.cat 参数&#xff1a;-n&#xff1a;显示行号-s&#xff1a;压缩连续的空行&#xff0c;只显示一个空行2.chattr 改变文件属性 语法&#xff1a;chattr [-RV] [/-/<属性>][文件或目录] 属性&#xff1a;a&#xff1a;让文件或目录仅供附加用途i&#xff1a;不得任意更…

MediaPipe人体姿态、手指关键点检测

MediaPipe人体姿态、手指关键点检测 文章目录 MediaPipe人体姿态、手指关键点检测前言一、手指关键点检测二、姿态检测三、3D物体案例检测案例 前言 Mediapipe是google的一个开源项目&#xff0c;用于构建机器学习管道。   提供了16个预训练模型的案例&#xff1a;人脸检测、…

基于级联深度学习算法的前列腺病灶检测在双参数MRI中的评估| 文献速递-基于深度学习的乳房、前列腺疾病诊断系统

Title 题目 Evaluation of a Cascaded Deep Learning–based Algorithm for Prostate Lesion Detection at Biparametric MRI 基于级联深度学习算法的前列腺病灶检测在双参数MRI中的评估 Background 背景 Multiparametric MRI (mpMRI) improves prostate cancer (PCa) de…

从西安出发,走向世界——西安国际数字影像产业园跻身全国十大产业园区行列

西安&#xff0c;作为中国历史文化名城&#xff0c;不仅以其丰富的历史遗产闻名于世&#xff0c;还逐渐成为现代科技和产业发展的新高地。产业园区成为推动经济增长和创新发展的重要引擎&#xff0c;西安国际数字影像产业园&#xff0c;正怀揣着雄心壮志&#xff0c;向着全国十…