From the std::default::Default docs:
#[derive(Default)]
struct SomeOptions {
foo: i32,
bar: f32,
}
fn main() {
let options = SomeOptions { foo: 42, ..Default::default() };
}
What is the .. prefix doing to the returned value of Default::default() and why is it necessary here? It almost seems like it's acting as a spread operator, but I'm not sure. I understand what ..Default::default() is doing -- filling in the remaining struct parameters with the default values of SomeOptions, but not how .. works. What is the name of this operator?
This is the struct update syntax. It is "needed" only to have a succinct way of moving / copying all of the members of a struct to a new one, potentially with some small modifications.
The "long" way of writing this would be:
let a = SomeOptions::default();
let options = SomeOptions { foo: 42, bar: a.bar };
You could indeed think of it similar to the JavaScript "spread" operator, but Rust's nuances of ownership and strong typing still come into play, so it's not as widely used. For example, you can't use this syntax to go between values of different types.
Related
Recently I was reading about the match keyword in the Rust Book. What confused me was the difference between Binding and Destructuring. In my understanding, both of these provide a way to access variables in an expression. Binding can specify a range matching, but you can achieve it with Destructuring and Guards. So can someone show some cases that only Binding can do or explain the real difference between these two concepts?
Here you can see one scenario when a binding is needed because destructuring doesn't satisfy our current need. If we simply destructure the struct we get access to the inner field of the struct. This means that the values used on the right hand side in the match arm won't have access to the methods defined on the struct.
In my example I also match against a specific value of ex.value, this is of course not necessary and can be done with a guard instead, this way is however more concise if the condition isn't very complex.
struct Example {
some_value: i32,
some_other_value: String
}
impl Example {
pub fn some_fn(&mut self) {}
}
fn main() {
let ex = Example { some_value: 42, some_other_value: "Foobar".to_string() };
match ex {
mut new_ex # Example { some_value: 43, .. } => new_ex.some_fn(),
Example { some_value: first, some_other_value: second } => println!("first value: {}\nSecond value: {}", first, second),
}
}
I'm doing something with MaybeUninit and FFI in Rust that seems to work, but I suspect may be unsound/relying on undefined behavior.
My aim is to have a struct MoreA extend a struct A, by including A as an initial field. And then to call some C code that writes to the struct A. And then finalize MoreA by filling in its additional fields, based on what's in A.
In my application, the additional fields of MoreA are all integers, so I don't have to worry about assignments to them dropping the (uninitialized) previous values.
Here's a minimal example:
use core::fmt::Debug;
use std::mem::MaybeUninit;
#[derive(Clone, Copy, PartialEq, Debug)]
#[repr(C)]
struct A(i32, i32);
#[derive(Clone, Copy, PartialEq, Debug)]
#[repr(C)]
struct MoreA {
head: A,
more: i32,
}
unsafe fn mock_ffi(p: *mut A) {
// write doesn't drop previous (uninitialized) occupant of p
p.write(A(1, 2));
}
fn main() {
let mut b = MaybeUninit::<MoreA>::uninit();
unsafe { mock_ffi(b.as_mut_ptr().cast()); }
let b = unsafe {
let mut b = b.assume_init();
b.more = 3;
b
};
assert_eq!(&b, &MoreA { head: A(1, 2), more: 3 });
}
Is the code let b = unsafe { ... } sound? It runs Ok and Miri doesn't complain.
But the MaybeUninit docs say:
Moreover, uninitialized memory is special in that the compiler knows that it does not have
a fixed value. This makes it undefined behavior to have uninitialized data in a variable
even if that variable has an integer type, which otherwise can hold any fixed bit pattern.
Also, the Rust book says that Behavior considered undefined includes:
Producing an invalid value, even in private fields and locals. "Producing" a value happens any time a value is assigned to or read from a place, passed to a function/primitive operation or returned from a function/primitive operation. The following values are invalid (at their respective type):
... An integer (i*/u*) or ... obtained from uninitialized memory.
On the other hand, it doesn't seem possible to write to the more field before calling assume_init. Later on the same page:
There is currently no supported way to create a raw pointer or reference to a field of a struct
inside MaybeUninit. That means it is not possible to create a struct by calling
MaybeUninit::uninit::() and then writing to its fields.
If what I'm doing in the above code example does trigger undefined behavior, what would solutions be?
I'd like to avoid boxing the A value (that is, I'd like to have it be directly included in MoreA).
I'd hope also to avoid having to create one A to pass to mock_ffi and then having to copy the results into MoreA. A in my real application is a large structure.
I guess if there's no sound way to get what I'm after, though, I'd have to choose one of those two fallbacks.
If struct A is of a type that can hold the bit-pattern 0 as a valid value, then I guess a third fallback would be:
Start with MaybeUninit::zeroed() rather than MaybeUninit::uninit().
Currently, the only sound way to refer to uninitialized memory—of any type—is MaybeUninit. In practice, it is probably safe to read or write to uninitialized integers, but that is not officially documented. It is definitely not safe to read or write to an uninitialized bool or most other types.
In general, as the documentation states, you cannot initialize a struct field by field. However, it is sound to do so as long as:
the struct has repr(C). This is necessary because it prevents Rust from doing clever layout tricks, so that the layout of a field of type MaybeUninit<T> remains identical to the layout of a field of type T, regardless of its adjacent fields.
every field is MaybeUninit. This lets us assume_init() for the entire struct, and then later initialise each field individually.
Given that your struct is already repr(C), you can use an intermediate representation which uses MaybeIninit for every field. The repr(C) also means that we can transmute between the types once it is initialised, provided that the two structs have the same fields in the same order.
use std::mem::{self, MaybeUninit};
#[repr(C)]
struct MoreAConstruct {
head: MaybeUninit<A>,
more: MaybeUninit<i32>,
}
let b: MoreA = unsafe {
// It's OK to assume a struct is initialized when all of its fields are MaybeUninit
let mut b_construct = MaybeUninit::<MoreAConstruct>::uninit().assume_init();
mock_ffi(b_construct.head.as_mut_ptr());
b_construct.more = MaybeUninit::new(3);
mem::transmute(b_construct)
};
It is now possible (since Rust 1.51) to initialize fields of any uninitialized struct using the std::ptr::addr_of_mut macro. This example is from the documentation:
You can use MaybeUninit, and the std::ptr::addr_of_mut macro, to
initialize structs field by field:
#[derive(Debug, PartialEq)] pub struct Foo {
name: String,
list: Vec<u8>, }
let foo = {
let mut uninit: MaybeUninit<Foo> = MaybeUninit::uninit();
let ptr = uninit.as_mut_ptr();
// Initializing the `name` field
unsafe { addr_of_mut!((*ptr).name).write("Bob".to_string()); }
// Initializing the `list` field
// If there is a panic here, then the `String` in the `name` field leaks.
unsafe { addr_of_mut!((*ptr).list).write(vec![0, 1, 2]); }
// All the fields are initialized, so we call `assume_init` to get an initialized Foo.
unsafe { uninit.assume_init() } };
assert_eq!(
foo,
Foo {
name: "Bob".to_string(),
list: vec![0, 1, 2]
}
);
I'm trying to use a generic datatype where one of the types is not needed (edge weights in a graph). I've been thinking to use the never type for this, which would look something like this:
#![feature(never_type)]
struct Foo<T> {
bar: T
}
impl<T> Foo<T> {
fn foo(&mut self, bar: T) {
self.bar = bar;
}
}
fn main() {
let mut foo: Foo<!> = Foo { bar: "nada" };
foo.foo("nada");
}
This obviously results in a type-mismatch for the "nada" placeholders, but just typing nothing will cause other errors. Is ! the right type to use here, and if so, what's the correct syntax?
I've gotten it to work using () instead of !, but I'm a bit unsure as to whether that's the proper choice of type. I believe in terms of efficiency it should make no difference, as () has no memory footprint?
() is the right choice. It is a type with a single value (also named ()), so it has a value, but contains no information.
! doesn't have any value, so if you put it in a struct the struct type doesn't have a value either and is basically unusable.
Is this just a current limitation or is there a technical reason? As generic functions get compiled to specialized code, I don’t see what should prevent it from working. It also works fine in the main function.
Example (playground):
#![feature(associated_consts)]
trait HasNumber<T> {
const Number: usize;
}
enum One {}
enum Two {}
enum Foo {}
impl<T> HasNumber<One> for T {
const Number: usize = 1;
}
impl<T> HasNumber<Two> for T {
const Number: usize = 2;
}
fn use_number<T, H: HasNumber<T>>() {
let a: [u8; H::Number] = unsafe { ::std::mem::uninitialized() };
}
fn main() {
let a: [u8; <Foo as HasNumber<One>>::Number] = unsafe { ::std::mem::uninitialized() };
println!("{}", <Foo as HasNumber<One>>::Number);
println!("{}", <Foo as HasNumber<Two>>::Number);
}
Short answer: It's not implemented yet, since it's hard to get right. There's even an open RFC named "Constants that depend on type parameters in generic code" for it.
Long answer:
This used to be a compiler-bug that caused the compiler to crash. It was "fixed" by #quantheory in PR 25091 by making this an error instead of a crash. #quantheory commented that
I haven't been able to deal with the array size or recursion issues yet for associated consts, though my hope was that the change I made for range match patterns might help with array sizes, too.
#quantheory also notes that this will stay an error until something along the lines of RFC 1062 is merged. Comments on the RFC are always appreciated, as they might hilight forgotten use-cases.
I'm facing an issue in Rust I have not yet found an answer to:
mismatched types: expected `[int]`, found `[int, .. 0]`
My code looks like:
struct Foo {
bar: [int]
}
And I'm trying to set it to an empty slice:
Foo {
bar: []
};
The types should be right, but maybe the size isn't.
Any ideas? I suspect it's something little.
Until dynamically sized types are implemented properly, you can't use bare [T] as a struct field, and even when they will be implemented, you probably wouldn't want it.
It seems you want to store an array into a struct, right? There are two ways to do it in Rust, depending on who owns the array content.
When the struct instance itself should own the data, then the simplest way is to use Vec<T>:
struct Foo {
bar: Vec<int>
}
You create its instance like this:
Foo {
bar: vec![1, 2, 3]
}
When the struct instance should only borrow the data, you should use a slice, &[T]:
struct Foo<'a> {
bar: &'a [int] // or &'a mut [int] if you need to modify contents
}
Then you create it like this:
let data: Vec<int> = ...; // obtained from somewhere
// slices can only be taken from existing data, e.g. Vec<T>, or be &'static
Foo {
bar: data.as_slice() // or as_mut_slice() for &mut [int]
}
I really recommend you reading excellent official guide which explains difference between owned vectors and slices and many more things.