作为练习,我正在Rust中编写一个简单的网络协议实现。它将从插槽中读取协议数据单元到内存,并继续使用适当的字段将其组件解析为Rust struct
。
可以用于解析的内存块的最佳类型是什么?我应该能够调用单独的函数以不同的偏移量解析它的各个部分。在C语言中,我将使用简单的const char *
。看起来Rust中的原始指针是可能的,但是并没有提供任何额外的安全益处,因为对它们的大多数操作都是不安全的,并且没有边界检查。
另一方面,我想将PDU块作为连续的内存块保留在堆中,就像从套接字读取的一样。换句话说,我不会增加任何表示开销。
答案 0 :(得分:0)
如果您要为堆分配字节的不可变缓冲区Vec<u8>
是显而易见的选择。
从您的问题出发,我怀疑您可能认为Vec的开销过多-并非如此:
它仅包含指向分配的堆内存和大小的指针。实际上,如果您想要一个安全的地方来存储协议消息,那是您可以避免的最低要求
符合生锈的理念:您只需为使用的功能付费。
因为它是一个基本的构建基块,所以std库设计人员对它的设计做出了很多保证,从而可以以非常低的开销方式使用它。我建议阅读上面链接的std库文档-有关这些保证的部分。
我可以将其设为只读吗?
是的,除非声明mut
,否则rust中的所有变量都是不可变的。您甚至可以从可变变量开始(如果您打算填充缓冲区开始时是必需的),然后将其重新绑定到不可变变量。
索引访问的效率也如何?例如,重复执行vec [n]版本,一次在C语言中计算vec + n,然后重复使用。
在担心这一点之前,我建议您以最清晰,最合逻辑的方式编写代码。编译器将进行优化,这些优化可能会使这些问题变得毫无意义。分析后,如果您遇到性能问题,请确保可以进行一些调整。
如果您想多次访问单个元素,则可以对其进行引用:
let el = &buf[n];
然后使用*el
来引用元素。
如果要顺序移动缓冲区,请使用迭代器,而不要顺序索引字节。迭代器是在内部使用指针实现的。
如果您想绕过缓冲区的一部分而不进行复制,请切一块:
let s1 = &buf[10..12];
// s1 now contains a slice of bytes 10 through 12
同样,切片是低开销的:指向起点和长度的指针。
以上所有都是安全代码。还有一些不安全的功能(例如get_unchecked
可以在不进行边界检查的情况下访问元素)。如果确实需要,甚至可以使用as_ptr()
获得原始指针。