背景
在这之前,我其实断断续续学过一些 Rust,但是作为前端程序员,日常没有较多的场景使用,所以一直处于纸上得来终觉浅的阶段。
本系列文章会每周更新一次,目前会通过 https://exercism.io/ 的小练习 & Rust By Examples 来熟悉理解 Rust 的语法,以及用小短文(题面+收获)的形式记录前端程序员视角学习 Rust 过程中的想法。后续题目做完,会通过使用&解析 yew 来深入学习 Rust。
Rust 的学习曲线真的挺抖的,以赛代练的学习方式可能不适合 Rust,如果不对 Rust 的语法和概念有一定的了解或者使用很可能会望码兴叹。所以,文章里肯定有很多因为我太弱而产生的错误~大佬们要是发现了,求指点~~~
Q1:Leap
题面
这道题的核心是判断输入是否为闰年。
收获
本次练习主要是回顾熟悉了下 Rust 里条件判断的写法,在 JS 里习惯给 if 的条件加上 (),在 Rust 里是不需要的。 在执行了 cargo clippy --all-targets 之后 Rust 的 lint 工具也会检测提示错误。
Q2:Raindrops
题面
这道题的核心是不同条件下字符串的输出不同。
收获
1. 字符串连接方式
(1) 字符串类型变量创建方式
目前用了两种,分别是:
创建空字符串类型
String::new()
创建一个有初始值的字符串类型
String::from("init")
(2) 连接方式
目前使用到了两种,分别是:
push_str or push
前者是向后添加字符串,后者是向后添加字符
eg.0 result.push_str("Hi")
eg.1 result.push('h')
传统 + 连接
eg.0 result += "Hello"
2. 数字、字符串之间的类型转换
类型转换一般分为基本类型转换和复杂类型转换。
基本类型转换
基本类型转换一般会用到 as 或者在 unsafe 块中使用 transmute。
复杂类型转换
(1) 数字转字符串
由于基本类型都实现了 to_string 的方法,这个类似于 JS 中的 toString。
eg.0 target.to_string()
(2) 字符串转数字
可以使用 parse 方法解析字符串。
eg.0 target.parse::()
参考
Q3:Nth Prime
题面
这道题的核心是通过索引返回素数列表中指定的值。
收获
本次练习单从题面来看不是特别曲折 -- 通过索引获取到对应的素数。这道题的核心在于获得指定长度的素数列表。
第一次的想法
考虑到函数的性能以及可能存在复用的场景。我的想法是把素数列表存在内存里,每次调用先去看内存里的素数列表够不够用,如果不够的话再去扩展内存中的素数列表,然后返回指定的素数。如果够用的话,直接根据索引返回指定的素数。
但是,这个可能是 JS 里的惯性思维的想法。在 Rust 里,没法去定义一个内存里可变的变量。即我的做法是:
constPRIMES: Vec=Vec::new();pubfn nth(n: u32)-> u32 {}
然后我发现,在函数调用的时候,PRIMES.push 压根没法给 Vector 加入新值。这个表现和 JS 是完全不同的。严格意义上而言,Rust 的 const 是更加符合不可变的定义的。JS 的 const 只是针对变量,即 const a = {},此时 a 不能再赋其他值,但是依然可以改变对象里成员,比如 a.x = 1。
基于此,这个思路就算作废了。
第二次的想法
既然没法通过内存优化重复性获取素数列表的行为,那就只能每次调用都收集一遍了。
其中的收获是,对于 Vector 而言,它的 Index 类型实现自 Trait std::ops::Index,从实现来看 primes[index] 的 index 的类型必须是 usize。这一点而言,相较于弱类型的 JS 也是使用习惯的不同之处。
参考