type
status
date
slug
summary
tags
category
icon
password

variables6.rs

关于const:
Rust的常量必须加类型。那为什么常量不推导呢? 这是因为故意这样设计的,指定类型就不会因为自动推导类型出问题。

primitive_types3.rs

数组(array)的三要素:
  • 长度固定
  • 元素必须有相同的类型
  • 依次线性排列
数组必须要初始化,以下这种写法会报错:
改为这样就编译通过:

vecs2.rs

iter_mut():
iter_mut() 创建一个可变引用迭代器。当你想要修改集合中的元素时,应使用 iter_mut()。iter_mut() 返回的迭代器将生成集合中每个元素的可变引用。

move_semantics2.rs

方法1:
将vec0的内容clone一份传进函数,然后返回值的所有权交给vec1,此时vec1=[22, 44, 66],vec0=[]
然后再把vec0的内容clone一份传进函数,然后返回值的所有权交给vec0,此时vec1=[22, 44, 66],vec0=[22, 44, 66]
这个时候不管是vec0还是vec1都拥有一片自己的堆上的空间,二者互不相关,因此vec1.push(88)只会改变vec1的值,且vec0的值也还存在
方法2:
首先,创建了vec0的一个可变引用&mut vec0,将这个可变引用传入函数,函数接受一个可变引用类型,然后对其进行操作,也就是操作了vec0指向的那片堆,因此在函数内部,vec0就已经变成了[22, 44, 66]
然后最后返回vec.to_vec(),相当于又创建了一个新的vec,作为vec1绑定的值,因此vec1和vec0又变成了互不相关的

move_semantics4.rs

这个的意思就是函数不再接收参数,而是直接在里面新创建一个包含[22, 44, 66]的vector返回

structs3.rs

结构体,有几点值得注意:
  1. 初始化实例时,每个字段都需要进行初始化
  1. 初始化时的字段顺序不需要和结构体定义时的顺序一致
需要注意的是,必须要将结构体实例声明为可变的,才能修改其中的字段,Rust 不支持将某个结构体某个字段标记为可变。
结构体方法:
  • Unlike functions, methods are defined within the context of a struct,and their first parameter is always self, which represents the instance of the struct the method is being called on.
  • we still need to use the & in front of the self shorthand to indicate that this method borrows the Self instance, just as we did in rectangle: &Rectangle. Methods can take ownership of self, borrow self immutably, as we’ve done here, or borrow self mutably, just as they can any other parameter.
  • 方法参数里面不止&self:package.get_fees(cents_per_gram)
    • 比如这个,get_fees是结构体的方法,它在结构体里面是这样定义的:
      也就是说,第二个参数跟在&self后面就好了,在外部调用结构体时只需要传入那个另外的参数
例子:

enums2.rs

更为复杂的枚举:
Move:包含了一个匿名结构体
Echo:包含了一个String
ChangeColor:包含了三个整数
Quit:没有关联任何数据

enums3.rs

模式匹配和模式绑定

strings3.rs

  • 字符串的字面量是切片
    • 一般写字符串可以这样写:let s = "Hello, world!";
      实际上,s 的类型是 &str,因此你也可以这样声明:let s: &str = "Hello, world!";
  • String转&str:取引用即可
    • &str转String:"hello,world".to_string()或者String::from("hello,world")
    • String的操作(必须把String声明为mut)
      • 由于 String 是可变字符串,因此只有String 这种字符串可以被操作更改
      • push(),在末尾追加字符;push_str() ,在末尾追加字符串
        • 这两个方法都是在原有的字符串上追加,并不会返回新的字符串,即返回值是()
      • insert() 方法插入单个字符,insert_str() 方法插入字符串字面量
        • 也是在原有的字符串上面操作,没有返回值
      • replace该方法可适用于 String 和 &str 类型
        • 该方法是返回一个新的字符串,而不是操作原来的字符串

    hashmaps2.rs

    问题1:
    关于hashmap的更新实例中:为什么修改count的值就可以修改hashmap的键值呢?
    解答:
    map.entry(word) 返回了一个 Entry 枚举类型的值,该枚举有两个变体:OccupiedVacantEntry 枚举表示 HashMap 中某个键对应的条目。
    当调用 or_insert 方法时,如果 word 对应的条目已经存在,则 or_insert 方法会返回该条目的值的可变引用(Occupied 变体),如果该条目不存在,则会在 map 中插入一个新的键值对,然后返回新插入的值的可变引用(Vacant 变体)
     
    问题2:
    这道题里面有这样一个语句:
    其中,basket是这样来的:
    所以,为什么basket已经是一个hashmap了,还要用*解引用呢?
    解答:
    *解引用解的不是basket,而是basket.get(&Fruit::Apple),因为get会返回一个指向该条目键值的引用
    跟这段代码一个道理:
    or_insert()会返回一个指向该条目键值的引用,因此也需要把它解引用来跟5比较

    quiz2.rs

    这道题主要注意Append这个命令:迭代器是向量中每个元素的引用(想想这是肯定的,不然在for循环里面所有权都丢失了的话有点太危险),而这种引用默认就是不可变引用,那么使用String类型的push_str()自然就是要报错的,因为这个方法是改变原字符串而不是返回一个新的字符串。

    options2.rs

    主要是if let语句和while let语句的使用
    首先,Option实际上是一种枚举类型,包含两个枚举成员:
    所以下面代码中的if let Some(word) = optional_target {}实际上就是将optional_target这个枚举类型的值结构到word上,然后进行一个操作
    while let语句也是一个道理,由于optional_integers的元素都是Some类型的变量,因此首先要把optional_integers的值解构到Some(integer)上,然后再进行操作,因此出现一个Some包裹一个Some
    关于if let的详细讲解

    options3.rs

    ref和&:

    errors2.rs

    关于errors:
    • 关于parse:
      • parse返回的是一个Result枚举类型,成功的话将会是Result::Ok(),失败是话是Result::Err,因此想获取parse成功时返回的正确值,需要将返回值unwrap()
    而做题的时候这个例子,返回的错误类型是std::num::ParseIntError
    还可以用?:

    errors3.rs

    在函数里面使用?:
    因为?的逻辑是这样的:
    如果返回的不是Err,就正常运行并且将Result枚举类型的值结构给cost
    但如果返回的是Err,函数就会立刻终止,然后返回一个Result::Err类型的值,因此必须给函数设置返回值
    但是在main函数里面返回一个Result::Ok(String::from("implement success!")) 是不合法的,因为main函数通常有两种有效的返回类型:()(表示成功)和Result<(), E>(表示成功或出现错误)。main函数的返回类型必须实现Termination trait,该trait规定了程序的终止行为

    errors4.rs

    可以像这样用匹配:
    但感觉这里也可以直接if判断:

    errors6.rs

    转换错误类型:将标准库定义的错误类型转换为自定义的ParsePosNonzeroError
    关于map_err:
    • Maps a Result<T, E> to Result<T, F> by applying a function to a contained Err value, leaving an Ok value untouched.
      • 也就是不触发错误返回,而是等待下一步对这个错误的处理
      代码:
      • 首先s.parse()尝试将s进行转换:
        • 如果出错的话,map_err()就会返回ParsePosNonzeroError::from_parseint 这个自定义的错误类型然后直接返回,而不是ParseIntError
        • 如果没出错,map_err() 就会返回一个Result::Ok(value)作为s转换后的值——因此后面一定要加?,不然出错的情况确实可以正常返回,但是没出错时Result类型的值是无法与i64类型的x绑定的,而?可以将正常返回的值直接unwrap
      • 然后x被成功绑定一个i64类型的整数,就需要判断x是否满足非负数,因此创建一个PositiveNonzeroInteger 类型的结构体,x的值作为结构体的值,然后调用结构体方法new()
        • 如果new成功返回Ok(PositiveNonzeroInteger(x as u64)),那么map_err()就返回这个Result::Ok类型的值
        • 如果new出错了返回了一个Result::Err类型的值,那么map_err()就返回ParsePosNonzeroError::from_creation 这个自定义的错误类型然后直接返回,而不是CreationError

      generics2.rs

      使用泛型

      traits5.rs

      特征的多重约束

      quiz3.rs

      关于格式化字符串format!:并不是所有的泛型都可以用这个函数,必须要有Display特征的泛型才可以,因此使用T: Display这个特征约束
      pub fn notify<T: Summary>(item1: &T, item2: &T) {}
      像这段代码的意思就是:约束T必须具有特征Summary,且item1和item2都是T类型的引用

      lifetimes3.rs

      关于结构体的生命周期:
      不仅仅函数具有生命周期,结构体其实也有这个概念,只不过我们之前对结构体的使用都停留在非引用类型字段上。细心的同学应该能回想起来,之前为什么不在结构体中使用字符串字面量或者字符串切片,而是统一使用 String 类型?原因很简单,后者在结构体初始化时,只要转移所有权即可,而前者,抱歉,它们是引用,它们不能为所欲为。
      既然之前已经理解了生命周期,那么意味着在结构体中使用引用也变得可能:只要为结构体中的每一个引用标注上生命周期即可:
      结构体 ImportantExcerpt 所引用的字符串 str 生命周期需要大于等于该结构体的生命周期

      iterators2.rs

      迭代器:
      • 迭代器是会被消耗的:
        • 当使用了next(),迭代器就会被消耗,相当于取出了那一个元素,那个元素其实已经不在迭代器里面了,因此最开始我直接将first转换为大写后直接返回了迭代器剩余的元素,这会导致返回的字符串没有预期的第一个字符

      iterators4.rs

      用迭代器实现递归:使用消费者适配器的方法
      在 Rust 中,(1..=num) 是一个范围(Range)表达式,表示从1到num(包括num本身)的一个范围。这个范围实际上是一个迭代器,它可以生成从1到num的所有数字序列。
      在这种情况下,我们可以通过 (1..=num) 创建一个包含从1到num的数字序列的迭代器。然后,我们调用迭代器的 product() 方法,这个方法将迭代器中的所有元素相乘,得到它们的乘积作为结果。
      因此,(1..=num).product() 这个语句的意思是:先生成从1到num的数字序列迭代器,然后计算这个序列中所有数字的乘积,最终得到阶乘的结果。

      iterators5.rs

      关于闭包和迭代器方法的使用
      不用循环,找出map里面有多少个键值为value的元素
      • .values():使用了HashMap的value方法,获取了一个包含所有键值的迭代器。
        • pub fn values(&self) -> Values<'_, K, V>一个以任意顺序访问所有值的迭代器。 迭代器元素类型为 &'a V ,即对键值的引用
      • .filter()创建一个迭代器,该迭代器使用闭包确定是否应产生元素。给定一个元素,闭包必须返回 true 或 false。返回的迭代器将仅生成闭包为其返回 true 的元素。
      • .count() :消耗迭代器,计算迭代次数并返回它。此方法将反复调用 next,直到遇到 None并返回它看到 Some 的次数。 请注意,即使迭代器没有任何元素,也必须至少调用一次 next
       
      返回一个所有哈希表里面键值为指定状态的数量和:
      • .map() :Iterator特征的函数,获取一个闭包并创建一个迭代器,该迭代器在每个元素上调用该闭包。
      • 首先创建collection的迭代器,再使用map使得迭代器上的每个元素都调用count_iterator(),对于每个哈希表都计算键值为progress的个数
      • .sum() :将迭代器里面的每个元素相加,所以这么写也是对的:
      数组Computer Networking Notes
      • Giscus