< 返回版块

elderhammer 发表于 2023-09-19 16:43

Tags:unsafe, DSA

之前看了《Learning Rust With Entirely Too Many Linked Lists》,算是了解了 unsafe。 现在一边看 DSA 一边写代码实践,会包含 unsafe,本意是顺带加强 Rust 的学习。 不过写 unsafe 很费劲,结果就是大概40%的时间学习 DSA,60%的时间在想怎么写 unsafe。

想请教下各位大佬,有没有作为过来人的经验:

  1. 用 Rust unsafe 继续实践下去,花时间等熟悉了写起来就快了
  2. 还是换一种语言来实践,例如 go、python 之类的

评论区

写评论
asuper 2023-10-09 09:25

学C主要是理解指针、内存这些,单纯拿本书看而不写实际项目,可能也不太能理解,学点简单的汇编我觉得可能更快见效

GUO 2023-09-21 11:45

也没什么技窍,刚开始是对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更轻松更优雅的解决了。

...

作者 elderhammer 2023-09-21 11:35

是的,一知半解 ORZ

谢谢指导,快乐老家,:D

--
👇
Bai-Jinlin: rust的unsafe操作什么...

Bai-Jinlin 2023-09-21 11:19

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费劲

作者 elderhammer 2023-09-21 10:17

除了学c,还有什么建议吗?

--
👇
Bai-Jinlin: 原来真有不会c就直接学rust的

--
👇
elderhammer: 好,我去学一下C

--
👇
Bai-Jinlin: 你肯定没学过c和cpp一类的,要不然也不能认为写unsafe费劲

Bai-Jinlin 2023-09-20 19:23

原来真有不会c就直接学rust的

--
👇
elderhammer: 好,我去学一下C

--
👇
Bai-Jinlin: 你肯定没学过c和cpp一类的,要不然也不能认为写unsafe费劲

作者 elderhammer 2023-09-20 15:58

好,我去学一下C

--
👇
Bai-Jinlin: 你肯定没学过c和cpp一类的,要不然也不能认为写unsafe费劲

viruscamp 2023-09-20 14:19

用 unsafe rust 写 DSA ,大概有这些事要做,难度递增:

  1. 写一个 unsafe 的程序,跑起来
  2. 提取数据结构的 lib
  3. 写完整的测试程序
  4. 写清楚 lib 的用法,限制(单例, thread safe, move safe) ====以上 C++ 和 Rust 难度差不多====
  5. 用 safe rust API 包装你的 lib, 用类型表达出用法和限制 (是否 Send Sync Copy 等等) 到这里你的lib基本上可以给别人用了
  6. 证明你的 safe lib 确实 safe miri 跑测试,以及程序正确性的数学证明等高级方法
Bai-Jinlin 2023-09-20 11:33

你肯定没学过c和cpp一类的,要不然也不能认为写unsafe费劲

作者 elderhammer 2023-09-20 09:59

我有一个情况是:需要用到 raw pointer,然后用 NonNull 包装获得 variance。写完之后,用 miri 检查提示有内存泄漏,想去排查但是不懂怎么弄。 后来直接用 Box,在 dereferencing raw pointer 的地方写 unsafe。

像你提到的“不断重构”,能不能讲讲你为什么用 NonNull,最后用什么方案来替代 NonNull ?

--
👇
GUO: 另外对于“绕不开才不得不使unsafe”,这也是看各人编程水平能力的,在甲认为是绕不开必须用unsafe,可能在乙看来可能不使用unsafe更轻松更优雅的解决了。

...

GUO 2023-09-20 09:22

另外对于“绕不开才不得不使unsafe”,这也是看各人编程水平能力的,在甲认为是绕不开必须用unsafe,可能在乙看来可能不使用unsafe更轻松更优雅的解决了。

我个人就有这样的亲身经历,刚开始的时候,好多地方觉得必须要使用unsafe才能实现,于是写了大量的unsafe代码块,还使用了大量的ptr::NonNull(用这个就少不了与unsafe打交道)。有时候我会思考,怎么看着觉得这么恶心,难道这就是我的rust最佳设计模式?

随着代码的深入,对rust了解的越来越多,发现之前的大多数unsafe是没有必要的,于是就是不断的在重构,对unsafe的依赖越来越少了。

GUO 2023-09-20 09:14

能不用尽量不用,如果绕不开一定要用 unsafe ,常规的搞法一般是搞一个safe 封装层,把unsafe限定在一个最小的范围之内,不要让unsafe到处传染。

当然了unsafe也不是洪水猛兽,一般使用unsafe就需要充分考虑它有可能的危险漏洞,并在代码中避免它,写覆盖面足够广的单元测试。

1 共 12 条评论, 1 页