我并不是很熟悉 Rust, 所以我产生了一些疑问(当然也希望喜欢 Rust 的人能解答我的问题). 因为我比较熟悉的是 C++ 和 Haskell, 所以会下意识的拿它们来比较.
Rust 在很多地方都吸取了教训, 但造出来的东西虽然正确, 细节上却常有疏忽, 反而更难用,这是我很不理解的, 而且 Rust 官方似乎还没有修复它们的意愿, 甚至连饼都没画给我, 所以我对 Rust 仍然是观望态度, 打算再等 2 ~ 3 年.
先说一些特别细节的问题, 这些问题任意拿出来一个都不算什么, 但合在一起却有理由让我退出.
auto oneToFive() -> std::vector<int32_t> { return {1, 2, 3, 4, 5}; }
在这个角度来看, 二者区别是不大的, Rust 这么写
fn oneToFive() -> Vec<i32> { vec![1, 2, 3, 4, 5]; }
然而 Rust 的宏对类型推断的支持并不是很好, 而且需要复杂的支持, 因此 HashMap, BTreeMap (和衍生出的两个 Set) 是没有字面量的, LinkedList 也没有. hashmap![]
这么长的东西本来就很丑, 而且标准库还没提供, 这就是问题了.
同时也透漏出另一问题, Rust 对 C++ 的很多 “设计缺陷” 做了编译期的保护, 你无法写出所谓的错误的代码, 这也是我们会被编译期教做人的原因. 而实际上是这个限制有点太过了, 如果你限制了三成正确的写法去提高正确性, 那我没什么问题, 但如果你限制九成正确的写法去提高正确性, 那我宁愿你不正确. 在 if
while
等表达式的参数可以省略括号时, Rust 是唯一一个强制省略括号的, 诸如 Swift 的其他语言, 均可以补上括号, 类似让人感到束手束脚的细节有很多.
作为初始化列表的宏其实真的用处不大, 因为我们总是可以这么写
auto some = Xxxxxx {1, 2, 3, 4, 5}; // C++ let mut some = xxxxxx![1, 2, 3, 4, 5]; // Rust
当然过程宏我不说了, C++ 没有, 需要用一些复杂的手段来处理.
范围区间
// 理想中 match x { ...0 => Equal::LT, 0 => Equal::EQ, _ => Equal::GT, } // 实际 match x { x if x < 0 => Equal::LT, 0 => Equal::EQ, x if x > 0 => Equal::GT, _ => /* 然后编译器还总觉得你不完备 */, }
那我干嘛不写 if-else 呢?
再比如 Optional, 很多语言都有, 甚至辣鸡 C++ 标准库里都有这么一个玩意. 但我们把 Kotlin 和 Swift 拽过来, 情况就大不相同的, 在 Rust 里, ?
被用来处理 Result, 而 Maybe 类型就完全没有语法糖.
let y = x ?? 3 // 默认值 a?.b()?.c() // 可选链 a! // 强制解包
&
和 &&
还有 &&&
到底都是啥, 什么时候需要一个, 什么时候需要两个, 同时还会伴随着一些诡异的代码 *x < 0
, x < &0
. RAII 确实很重要, 但是牺牲如此之大我觉得不值得, 我随时都会遇到各种类型不匹配的问题, 如果不是编译器友善的提醒我那些东西的类型, 恐怕我还要在上边花费更多时间. 这时候我对类型推断的疑惑就出现了, 当然我不知道 Rust 实现的到底是啥理论, 没见过我也不好说太多. 但是作为一门类型如此复杂的语言, 还坚持用 let 推断, 这就是我不好理解的地方了.首先, Rust 有很多明显该推= 出来的东西根本推断不出来, 我不知道为什么, 一些东西的类型非常明显, 属于一眼就能看出来的类型, Rust 却看不懂. 当编译器看不懂的时候, C++ 是很方便的. 只要前缀写上就可以, 而
let x: Vec<i32> = /* ... */
我能说这有点画蛇添足么. 当然很多语言都用后置类型, 但它们的类型非常简单, 比如 Kotlin, Swift, 它们几乎就没有推断不出来的东西. 我在写 Swift 的时候, 从来不会因为某个变量的类型不够明晰而疑惑, 但 Rust 过于复杂, 又采用了一个极其绕的实现, 这就是让我不舒服的地方.
Rust 可以根据上下文推断类型, 展现了高超的编译器技术, 但我宁愿希望它没有. 如果一个类型的推断是从五行开外的得来的, 那我的眼睛就很难 phrase 这段代码, 而且今后删改的时候就更难处理, 因为我删除某个代码, 甚至可能影响五行开外的推断.
王垠就 diss 过 Rust, 也说过这个不够明确的问题, 但王垠完全没有好好用过这门语言, 以至于出现了不少低级错误, 但对这点的分析我倒是很赞成, 如果他多用用, 很快就会发现这东西不仅是不够明确, 而是极其混乱.
Rust 可以通过函数参数的类型来推断其他类型, 这个功能更让我不理解, 当然 Rust 官方可以生成不喜欢重载(你咋不干脆声称你不喜欢 Ad-hoc 呢?), 因为不重载的函数才有助于这种推断. 然后我想请问: 官方在函数非自动柯里化, 对函数式支持不够好的情况下, 为什么仍然拒绝实现可选参数, 命名参数和不定数量参数?
当然, 还有一些我并不太喜欢的东西, 像 "Hello, World!.to_string()
...
如果用惯了 C++ 的人, 很可能会把 C++ 当成某种黑魔法, 有可能造成一些副作用, 需要人类主动的去控制. 而人们对 Rust 的期望是, 既能起到黑魔法的效果, 又能规避大部分错误. 于是它们把咒语写的极其复杂晦涩, 说十句都施不出来正确的魔法, 每个咒语都是绕口令.
那你觉得魔法师会用哪个呢?
本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度,google,bing,sogou 等
© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有