100个练习学习Rust!构文・整数・变量

news2024/11/16 15:47:09

前一篇文章

【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/2043061.html

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

相关文章

SpringBoot入门第一篇

目录 SpringBootSpring Boot核心特性Spring Boot应用结构目录结构样例目录结构讲解 Spring Boot版本更新概览升级建议总结 常见使用场景社区和资源常见疑问**Spring Boot的自动配置机制是如何工作的?****Spring Boot支持哪些常见的配置文件格式?****为什…

硬件设计-1/f噪声、均方根(RMS)噪声与等效噪声带宽

简介: 学习下噪声的知识,为什么写这个呢,因为前几年有次面试和别人谈到这个问题。 定义解释: 1/F噪声 高频下的噪声为白噪声(即其频谱密度不会随频率而变化)。这种情况适用于运算放大器的大 部分频率范围,但在低频率…

C语言问答进阶--2、C语言简介及基本的输入输出函数

C语言简介 Q:您好,能大体介绍下C语言吗? A:当然可以。C语言是一种计算机语言,它主要被用在系统编程里,可以说,C语言的产生就和操作系统的编写密不可分。 【C语言简要历史】 1978年由美国电话电报…

Redis7.0.15 主从复制、哨兵模式搭建

主从复制:master以写为主,slave以读为主,当master数据变化的时候,自动将新的数据异步同步到其他的slave数据库 1. Redis复制介绍: https://redis.io/docs/latest/operate/oss_and_stack/management/replication/ 读写…

Unity游戏开发001

Unity游戏开发 系列文章的目录: 第一章:Hello,Unity! “好读书,不求甚解;每有会意,便欣然忘食。” 本文目录: Unity游戏开发 Unity游戏开发前言今天我们来体验一下unity开发创建第一…

基于MMIO的Virtio流程分析——QEMU平台

目录 一、相关概念 1、Virtio 2、QEMU 3、KVM 4、MMIO 5、小结 二、QEMU中Virtio的实现方法 1、virtio_blk 2、virtio_net 三、Virtio Driver和Virtio Device 的初始化流程 1、Virtio Driver Init 2、Virtio Mmio Driver Init 3、Virtio Device Init (1) get dev…

培训第二十九天(python脚本使数据库读写分离,mysql主从开机自动同步,python操作数据库,MyCat插件的学习)

上午 1、python脚本实现数据库主从分离 # 引入模块 python链接mysql工具,驱动包,连接器import pymysql# python 类 类名 rwsplit,名字可以和文件名不一致# 三个函数,函数的标识 def 函数名 (self,参数列表):# __init__ 初始化函数&#xff…

详解最大比合并算法(Maximum Ratio Combining)

目录 一. 空间分集(space diversity) 二. 系统模型 三. 尝试性译码 3.1 选择性合并算法(selection combining) 3.2 简单相加 四. 最大比合并算法 4.1 合并信号 4.2 设计权重值w 五. 波束赋形 5.1 小结 5.2 与波束赋形的…

牛客小白月赛98

牛客小白月赛98 A 骰子魔术 链接:https://ac.nowcoder.com/acm/contest/85598/A 来源:牛客网 题目描述 jackle 正在给他的朋友表演一个关于骰子的魔术: jackle 会拿出一枚骰子,骰子的表面分别写上了从 1∽500 的数字&#xff0c…

Hadoop环境安装及HDFS初步使用

一、Hadoop原理 Hadoop是一个由Apache基金会所开发的分布式系统基础架构。用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。Hadoop实现了一个分布式文件系统( Distributed File System),其中一个组件是HDFS(Hadoop Distr…

【深度学习】【语音TTS】GPT-SoVITS v2 实战,训练一个人的音色,Docker镜像

文章目录 原理Dockerdocker push训练教程: https://www.yuque.com/baicaigongchang1145haoyuangong/ib3g1e/xyyqrfwiu3e2bgyk 原理 Docker 不用docker不行,不好分配显卡, 做个docker镜像: docker pull pytorch/pytorch:2.1.2

【数据结构与算法 | 图篇】Dijkstra算法(单源最短路径算法)

1. 前言 由图: 如果我们想要求得节点1到节点5(也可以是其他节点)的最短路径,我们可以使用Dijkstra算法。 2. 步骤与思路 1. 将所有顶点标记为未访问(顶点类的visited属性设置为false)。创建一个未访问顶点的集合。 2. 为每个顶…

Web开发:使用Abp.AutoMapper进行实体映射的demo

控制台程序为例&#xff0c;展示该demo 一、安装Nuget包 二、文件结构 三、AutoMapperProfile.cs&#xff08;映射规则&#xff09; using AutoMapper;namespace ConsoleApp1 {public class AutoMapperProfile : Profile{public AutoMapperProfile(){CreateMap<Student, T…

面向新人的 Java 面试问题(1-50)

1. Java 是否独立于平台&#xff1f;如果是&#xff0c;那么如何独立&#xff1f; 是的&#xff0c;Java 是一种独立于平台的语言。与许多编程语言不同&#xff0c;javac 将程序编译为字节码或 .class 文件。此文件独立于正在运行的软件或硬件&#xff0c;但需要在操作系统中预…

--- java 包装类 泛型 ---

包装类 因为在java中基本类型&#xff08;int char...&#xff09;不是继承值Object类&#xff0c;为了满足泛型的需要&#xff0c;于是给每种基本类型都设计了对应的包装类 基本类型包装类intInteger char CharacterbyteByteShortShortfloatFloatdoubleDoublelongLongboolea…

mars3D引用模型库以及图标配置

文章目录 一、icon总结 一、icon 引入基本场景后 还差几个样式引入 mars3D图标用的 https://fontawesome.dashgame.com/ 引入对应的 <link rel"stylesheet" href"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"&…

WebGIS开发中一些常见的概念

0. 坐标系投影 地理坐标系和投影坐标系是两种常用的坐标系统&#xff0c;它们各自有着独特的特性和应用场景。 0.1 地理坐标系 地理坐标系(Geographic Coordinate System&#xff0c; 简称 GCS)是以地球椭球体面为参考面&#xff0c;以法线为依据&#xff0c;用经纬度表示地…

双指针| Java | (hot100) 力扣283, 11, 15, 42做题总结

leetcode 11 盛最多水的容器 双层for循环暴力 超出时间限制 class Solution {public int maxArea(int[] height) {int h0;int v0;for(int i0; i<height.length; i) {for(int ji1; j<height.length; j) {h Math.min(height[i],height[j]);v Math.max(v, h*(j-i));}}…

【原创公式】【完全二叉树】叶结点的计算【数据结构】

完全二叉树叶结点的计算 【铺垫】1叶结点即度为0的结点 2完全二叉树中度为1的结点只可能有0或1个 3完全二叉树的设叶结点仅可能出现在最后2层 设有完全二叉树T 【区分】第k层有a个叶结点≠第k层有a个结点 &#xff08;1&#xff09;第k层有a个叶结点&#xff1a;T的形态不唯一&…

Mac电脑虚拟机安装win11教程

Mac分享吧 文章目录 效果一、准备工作二、安装步骤方法1&#xff1a;使用虚拟机自带的win11系统&#xff0c;选中系统软件--继续--安装&#xff0c;即可完成win11安装方法2&#xff1a;通过下载好的镜像安装Windows11系统。选择镜像文件位置&#xff0c;安装&#xff0c;配置1…