4 ms·
Without any unsafe code this is simply: let role = Role { name: "basic", flag: 1, disabled: false, }; The language tries to pr
by notpopcorn 5y ago
Without any unsafe code this is simply:
let role = Role {
name: "basic",
flag: 1,
disabled: false,
};
The language tries to prevent you from interacting with a `Role` object that's not fully initialized. `mem::zero()` could work, but then you'll have to turn the `&'static str` into an `Option<&'static str>` or a raw pointer, to indicate that it might be null. You could also add `#[derive(Default)]` to the struct, to automatically get a `Role::default()` function to create a `Role` with and then modify the fields afterwards, if you want to set the fields in separate statements for some reason:
let mut role = Role::default();
role.name = "basic";
role.flag = 1;
role.disabled = false;
And even with `MaybeUninit` you can initialize the whole struct (without `unsafe`!) with `MaybeUninit::write`. It's just that partially initializing something is hard to get right, which is the point of the article I guess. But I wonder how commonly you would really want that, as it easily leads to mistakes.
- ATsch 5y agoA much better way to do partial initialization is by splitting up the struct into multiple parts. This can be easily done in safe rust with Option, or MaybeUninit if you're really desperate for performance.
- deleted 5y ago[deleted]
- bodhiandpysics1 5y agoWhen dealing with unix syscalls, you actually sometimes need to pass structs that aren't fully initialized, or are initialized to zero with the exception of some fields. The quintessential example is the sigaction struct.
- pjmlp 5y agoAnother good example is Win32, in many cases only the length is initialized and the API does the rest, this allows them to change the ABI across versions without impacting the caller.
- ATsch 5y agoThat should work perfectly with multiple structs. Define #[repr("C")] struct MyThing { length: usize, data: MaybeUninit<MyInner> } Then initialize with sizeof(data) and MaybeUninit::uninitialized(). When the call is complete, assume_init() and access the fields of the result struct as normal.
- pjmlp 5y agoI see, thanks.
- ______-_-______ 5y agoExactly this. I'm not sure what the author's practical goal is with that code. He rejects #[repr(C)] a few times, so it's not FFI. Yes, working with uninitialized memory is tedious. But that isn't something you ever have to do. If you're translating some C to Rust, write it using Rust idioms, instead of trying to preserve every call to malloc/free and every access to uninitialized memory.
- jerf 5y agoThe point is to make points in a simple environment. Anything small enough to clearly make points about unsafe Rust is almost certainly small enough to be done in safe Rust, defeating the purpose.
- malf 5y agoIf it’s too big for an example, it’s almost certainly too big for “trust me, I know this is safe”.
- albrewer 5y agoI don't see how you can make this claim. An example is meant to be understandable after a cursory introduction and communicate an idea to the reader. If it takes me a day to understand the "example", it's not useful as an example, but real problems often take that long to completely understand in any language.
- flohofwoe 5y agoAlso, the C version should really look like this: const struct role r = { .name = "basic", .flag = 1, .disabled = false, }; (of course this doesn't give you uninitialized memory in case new items are added to the struct, but why would one ever want that?)
- scoutt 5y ago> The language tries to prevent you from interacting with a `Role` object that's not fully initialized. I remember that after reading the Rust book, one of the first things I tried to do was to load a struct from a file. Like pseudocode: struct MY_STRUCT my_struct; read(file, &my_struct, sizeof(my_struct)); 2 lines of code.... It should be simple, right? RiGhT?! Well, the first stackoverflow answer involved unsafe and a bunch of other stuff I didn't understand. And also I thought that as a beginner I shouldn't start fiddling with unsafe right away (otherwise, what's the point? I'm trying to move away from C). Then I learned that structs are not laid out as declared (OMG!), etc. So, thinking this went beyond my skills I left it aside and tried to make a nice console logging library for my projects. It should be simple! I tried to create a variadic function and you can guess how it went. I am out of luck with Rust.
- throwaway8948 5y ago>It should be simple, right? Well, no. If you want to have memory safe subset, you absolutely cannot initialize structs with random bag of bytes in general case. C let's you cut corners here, but in Rust you need to implement (de)serializing logic (no need for unsafe). >Then I learned that structs are not laid out as declared (OMG!), etc. >It should be simple! I tried to create a variadic function and you can guess how it went. This is only surprising if you have this weird assumption that things should work like they do in C + some extra.
- scoutt 5y ago> in Rust you need to implement (de)serializing logic Hmm. Well that sucks. It might be slower than reading into a struct directly (does more IO calls, there is more code to execute, probably uses more memory). My focus is on embedded applications, so "the less, the better". > no need for unsafe Can you point out an example on reading a bunch of structs from a file? Without std? Now I'm really curious. > you have this weird assumption You are probably right. I intended to use Rust in embedded as I said before so I thought a system language like Rust could fit. But you are right and the more I read (docs and comments like yours) I realize it's not C, and Rust may require extra steps and resources to achieve the same things I can do in C. With consequential hit on performance/code size/whatever, that it's a thing to consider seriously in constrained environments.