之前看了《Learning Rust With Entirely Too Many Linked Lists》,算是了解了 unsafe。 现在一边看 DSA 一边写代码实践,会包含 unsafe,本意是顺带加强 Rust 的学习。 不过写 unsafe 很费劲,结果就是大概40%的时间学习 DSA,60%的时间在想怎么写 unsafe。
想请教下各位大佬,有没有作为过来人的经验:
- 用 Rust unsafe 继续实践下去,花时间等熟悉了写起来就快了
- 还是换一种语言来实践,例如 go、python 之类的
1
共 12 条评论, 1 页
评论区
写评论学C主要是理解指针、内存这些,单纯拿本书看而不写实际项目,可能也不太能理解,学点简单的汇编我觉得可能更快见效
也没什么技窍,刚开始是对rust的不熟,总想绕开生命周期和所有权的限制,于是疯狂在rust中找C++的对标方案,就找到 NonNull 这种玩意儿,如果没有mut还好,一旦要mut ,就不得不与unsafe打交道,NonNull还有一个最大风险是内存泄露,很容易忘释放内存,用的越多风险越多,与退化到C/C++没什么区别。
后面想通了,之所以想绕开生命周期和所有权的限制,是因为还在用C++的思维来设计数据结构。后面把这些了解得差不多后,把要设计的数据结构生命周期理顺,其实都好解决,绝大多数 NonNull 都可以通过 &引用来替代,还有一些很好用的Cell,RefCell用于解决内部可变问题,等等,基本上都能绕开unsafce。
链表是个例外,要造轮子包装unsafe。
--
👇
elderhammer: 我有一个情况是:需要用到 raw pointer,然后用 NonNull 包装获得 variance。写完之后,用 miri 检查提示有内存泄漏,想去排查但是不懂怎么弄。 后来直接用 Box,在 dereferencing raw pointer 的地方写 unsafe。
像你提到的“不断重构”,能不能讲讲你为什么用 NonNull,最后用什么方案来替代 NonNull ?
--
👇
GUO: 另外对于“绕不开才不得不使unsafe”,这也是看各人编程水平能力的,在甲认为是绕不开必须用unsafe,可能在乙看来可能不使用unsafe更轻松更优雅的解决了。
...
是的,一知半解 ORZ
谢谢指导,快乐老家,:D
--
👇
Bai-Jinlin: rust的unsafe操作什么...
rust的unsafe操作什么*mut XXX,Option<NonNull>,transmute,说到底就是对应的c的各种操作,正常学过c或者cpp的理解和用起来这些东西甚至看看文档就能知道如何用,这种原始的用法才是快乐老家。
我感觉你现在有的问题很大程度就是没学过的c导致的不明白为什么有这些东西,以及没有明确rust中safe以及unsafe的边界。
--
👇
elderhammer: 除了学c,还有什么建议吗?
--
👇
Bai-Jinlin: 原来真有不会c就直接学rust的
--
👇
elderhammer: 好,我去学一下C
--
👇
Bai-Jinlin: 你肯定没学过c和cpp一类的,要不然也不能认为写unsafe费劲
除了学c,还有什么建议吗?
--
👇
Bai-Jinlin: 原来真有不会c就直接学rust的
--
👇
elderhammer: 好,我去学一下C
--
👇
Bai-Jinlin: 你肯定没学过c和cpp一类的,要不然也不能认为写unsafe费劲
原来真有不会c就直接学rust的
--
👇
elderhammer: 好,我去学一下C
--
👇
Bai-Jinlin: 你肯定没学过c和cpp一类的,要不然也不能认为写unsafe费劲
好,我去学一下C
--
👇
Bai-Jinlin: 你肯定没学过c和cpp一类的,要不然也不能认为写unsafe费劲
用 unsafe rust 写 DSA ,大概有这些事要做,难度递增:
你肯定没学过c和cpp一类的,要不然也不能认为写unsafe费劲
我有一个情况是:需要用到 raw pointer,然后用 NonNull 包装获得 variance。写完之后,用 miri 检查提示有内存泄漏,想去排查但是不懂怎么弄。 后来直接用 Box,在 dereferencing raw pointer 的地方写 unsafe。
像你提到的“不断重构”,能不能讲讲你为什么用 NonNull,最后用什么方案来替代 NonNull ?
--
👇
GUO: 另外对于“绕不开才不得不使unsafe”,这也是看各人编程水平能力的,在甲认为是绕不开必须用unsafe,可能在乙看来可能不使用unsafe更轻松更优雅的解决了。
...
另外对于“绕不开才不得不使unsafe”,这也是看各人编程水平能力的,在甲认为是绕不开必须用unsafe,可能在乙看来可能不使用unsafe更轻松更优雅的解决了。
我个人就有这样的亲身经历,刚开始的时候,好多地方觉得必须要使用unsafe才能实现,于是写了大量的unsafe代码块,还使用了大量的ptr::NonNull(用这个就少不了与unsafe打交道)。有时候我会思考,怎么看着觉得这么恶心,难道这就是我的rust最佳设计模式?
随着代码的深入,对rust了解的越来越多,发现之前的大多数unsafe是没有必要的,于是就是不断的在重构,对unsafe的依赖越来越少了。
能不用尽量不用,如果绕不开一定要用 unsafe ,常规的搞法一般是搞一个safe 封装层,把unsafe限定在一个最小的范围之内,不要让unsafe到处传染。
当然了unsafe也不是洪水猛兽,一般使用unsafe就需要充分考虑它有可能的危险漏洞,并在代码中避免它,写覆盖面足够广的单元测试。