Okay, so I am just starting learn a little bit of Rust and I am running to a pretty simple problem. I have a recursive type like this:
struct Tree {
root : i32,
children : Box<[Option<Tree> ; 100]>
}
Later, when I was trying to initialize Tree
hex.rs:30:29: 30:40 error: the trait `core::marker::Copy` is not implemented for the type `Tree` [E0277]
hex.rs:30 children : Box::new([None; 100])
^~~~~~~~~~~
error: aborting due to previous error
So, I added
#[derive(Copy)]
before the struct definition, but I got this error:
hex.rs:8:10: 8:14 error: the trait `Copy` may not be implemented for this type; field `children` does not implement `Copy` [E0204]
hex.rs:8 #[derive(Copy)]
^~~~
note: in expansion of #[derive]
hex.rs:8:1: 8:16 note: expansion site
error: aborting due to previous error
I am not entirely sure where to go from here. Is there an easy way to derive traits for recursive data types?
The problem is that Box doesn't support Copy. Copy states:
Types that can be copied by simply copying bits
However, a Box contains pointers to memory, and that memory will not be copied when you just copy the bits of the pointer.
When you are constructing your array, Rust only knows that you are going to put an Option in there. There isn't a way to have a enum only half-implement a trait.
Do you need to use a fixed-size array? Perhaps this would work better:
struct Tree {
root : i32,
children : Vec<Tree>
}
Your constructor can then use Vec::with_capacity:
impl Tree {
fn new(root: i32) -> Tree {
Tree { root: root, children: Vec::with_capacity(100) }
}
}
I'm afraid you won't be able to use static arrays and recursive types like that without unsafe. The reason is that array initializers require the array element type to be Copy because they initialize all elements with bytewise copies of the initial element, and your type can't be Copy because it contains Box, which is the only safe way to allow recursive types in Rust (well, there are also Vec and other similar containers, but they also need a heap allocation).
If you are not afraid of allocations, you can just as well use Vec:
struct Tree {
root: i32,
children: Vec<Tree>
}
Then the initialization could look like
Tree {
root: 0,
children: vec![]
}
Related
I am a beginner in Rust. I tried to write a linked list for practice.
Some sturct code:
type Link<T> = Option<Box<Node<T>>>;
pub struct List<T> {
head: Link<T>,
}
struct Node<T> {
elem: T,
next: Link<T>,
}
Peek function for List:
error code:
pub fn peek(&self) -> Option<&T> {
self.head.map(|ref node| {
&node.elem
})
}
The Rust compiler return: cannot return value referencing function parameter.
The following code is ok:
pub fn peek(&self) -> Option<&T> {
self.head.as_ref().map(|node| {
&node.elem
})
}
So I guess,
The error code is actually an abbreviation of the following code:
self.head.map(|node| {
let ref ref_node = node;
&ref_node.elem
})
Is my guess correct?
More, is there a similar abbreviation in Rust? Or abbreviation rules.
The error “cannot return value referencing function parameter” is sort of a red herring here; it has nothing to do with the fundamental problem, but just happened to be listed first. If you compile the code
type Link<T> = Option<Box<Node<T>>>;
pub struct List<T> {
head: Link<T>,
}
struct Node<T> {
elem: T,
next: Link<T>,
}
impl<T> List<T> {
pub fn peek(&self) -> Option<&T> {
self.head.map(|ref node| &node.elem)
}
}
then you will get two errors, the second of which is the reason this code doesn't work and you needed .as_ref():
error[E0507]: cannot move out of `self.head` which is behind a shared reference
--> src/lib.rs:14:9
|
14 | self.head.map(|ref node| &node.elem)
| ^^^^^^^^^ move occurs because `self.head` has type `Option<Box<Node<T>>>`, which does not implement the `Copy` trait
|
help: consider borrowing the `Option`'s content
|
14 | self.head.as_ref().map(|ref node| &node.elem)
| +++++++++
This error is the one from the root cause; Option::map consumes its input Option, which is not what we want to do here. Option::as_ref solves this by taking an &Option<T> (here, by implicit auto-reference turning self.head into &self.head) and returning a newly created Option<&T>, which can then be consumed by Option::map.
But, I understand that you want to know how the erroneous code produced the “cannot return…” error. Here's how:
We know that self.head is an Option<Box<Node<T>>>.
Calling Option::map() on that type means it expects a function FnOnce(Box<Node<T>>) -> &T.
That is, the closure is acting as a function which is given ownership of a Box<Node<T>>. So, within the closure, node is a local variable that owns the Box.
The body of the closure then attempts to return a reference to a field of the Node inside that box, which is an error E0515 since the box is owned by a local variable and is going to be dropped at the end of the function.
Your ref modifier does not change things, because whether a value is moved into a function is determined by the function's parameter types, not by what kind of pattern/binding the function body uses.
The error code is actually an abbreviation of the following code:
self.head.map(|node| {
let ref ref_node = node;
&ref_node.elem
})
Is my guess correct?
Yes and no. You can expand the code that way. But that's not the “real” code; it's rather that introducing the separate ordinary variable node before a more complex pattern is always valid, for function parameters. It's not something that the compiler does anyway; it's adding trivial code, in the same way that multiplying by 1 doesn't change a number. But, the fact that you can do this without changing the program is a consequence of the fact that function parameters are moved in regardless of what the function itself writes in its parameter patterns.
However, it wouldn't be possible to make your original code work by changing Rust function parameters to work that way. The function which is causing the problem is Option::map() applied to a borrowed struct field; that would always fail regardless of what the function passed to map() does, because Option::map() always consumes the Option given to it.
I am trying to use polymorphism in Rust but am having great difficulties. Here are my basic structures:
trait Constant { ... }
struct ConstantString { ... }
impl Constant for ConstantString { ... }
struct ConstantClass { ... }
impl Constant for ConstantClass { ... }
// other Constant implementations
struct JavaClass
constants: Vec<Box<dyn Constant>>
First, I cannot manage to downcast say a Constant to a ConstantString, even when using match.
Also, I cannot manage to go through the constants and initialize them, especially as they reference each other, so each initialization needs to go through the constants vector. I tried various versions of the following inside a JavaClass method:
for constant in self.constants.iter_mut() {
constant.init(&self);
}
to no avail, as I am hitting multiple borrow or immutable borrow errors.
But am I even using the right approach? Rust is behaving very differently than other languages when it comes to memory management.
After some further tries, here's how I worked it out. First of all, I got rid of the Constant trait and created a collection for each subtype, e.g.
pub struct JavaClass {
constants_class: HashMap<usize, ConstantClass>,
constants_string: HashMap<usize, ConstantString>,
constants_string_ref: HashMap<usize, ConstantStringRef>,
constants_method: HashMap<usize, ConstantMethod>,
constants_field: HashMap<usize, ConstantField>,
constants_name_type: HashMap<usize, ConstantNameType>
}
Also, by building those inside the JavaClass constructor I was able to avoid any mutable error. I found it was easier to manipulate collections declared locally than if they belong to self.
For some OpenGL code, I created a trait Vertex. currently it looks like this
trait Vertex: Sized + Clone {
//...
}
Because of the way Vertex's are used in my program, its very important that anything is a vertex uses the packed representation. If there is any padding it could potentially create problems. Is there any way I can constrain the Vertex trait to only types that use the packed representation? If need be, I could just define my own marker trait that I manually implement for everything that implements Vertex. It seems like something the compiler could easily surface and enforce properly, but I haven't been able to find any kind of representation trait. Thanks
This question gave me the impetus to finish a project I had lying around to do exactly this.
I just pushed it to crates.io. I've been using it for some similar work (dealing with some strange FFI's), but never published it.
It lets you write this code:
use repr_trait::Packed;
// Safety: Only safe to call when T has #[repr(packed)]
unsafe fn safe_when_packed<T>(_param: T) {
unimplemented!()
}
fn safe_wrapper<T: Packed>(param: T) {
// Safety: Safe because T is guaranteed to be #[repr(packed)]
unsafe {
safe_when_packed(param)
}
}
#[derive(Packed, Default)]
#[repr(packed)]
struct PackedData(u32, u8);
safe_wrapper(PackedData(123, 45));
But this is a compile error:
#[derive(Packed)]
struct NotPacked(u32, u8);
You would write your vertex trait as:
trait Vertex: Sized + Clone + Packed {
//...
}
Consider the following implementation:
pub struct BST {
root: Link,
}
type Link = Option<Box<Node>>;
struct Node {
left: Link,
elem: i32,
right: Link,
}
impl Link { /* misc */ }
impl BST { /* misc */ }
I keep getting the error:
cannot define inherent impl for a type outside of the crate where the type is defined; define and implement a trait or new type instead
I was able to find others had this same issue back in February, but there was seemingly no solution at the time.
Is there any fix or another way for me to implement my Link typedef in Rust?
Is there any fix
Not really. A type alias (type Foo = Bar) does not create a new type. All it does is create a different name that refers to the existing type.
In Rust, you are not allowed to implement inherent methods for a type that comes from another crate.
another way for me to implement
The normal solution is to create a brand new type. In fact, it goes by the name newtype!
struct Link(Option<Box<Node>>);
impl Link {
// methods all up in here
}
There's no runtime disadvantage to this - both versions will take the exact same amount of space. Additionally, you won't accidentally expose any methods you didn't mean to. For example, do you really want clients of your code to be able to call Option::take?
Another solution is to create your own trait, and then implement it for your type. From the callers point of view, it looks basically the same:
type Link = Option<Box<Node>>;
trait LinkMethods {
fn cool_method(&self);
}
impl LinkMethods for Link {
fn cool_method(&self) {
// ...
}
}
The annoyance here is that the trait LinkMethods has to be in scope to call these methods. You also cannot implement a trait you don't own for a type you don't own.
See also:
How do I implement a trait I don't own for a type I don't own?
I'd like to create a generic tuple struct Producer which can hold any type P which implements the trait Produce<T>, defined below. This produces the (expected) commented error:
trait Produce<T> {
fn get(&mut self) -> T;
}
// ERROR: parameter `T` is never used [E0392]
struct Producer<P,T>(P) where P: Produce<T>;
If this were a non-tuple struct, I could remedy this issue by adding a PhantomData<T> field and writing a constructor Producer::new(p: P) to hide this as an implementation detail. However, I'm using this type as one of a family of tuple structs in a Builder API, so using a conventional struct + constructor feels pretty out of place.
Is there any way to achieve this?
In many cases, you don't want to parameterize your trait, but instead want an associated type:
trait Produce {
type T;
fn get(&mut self) -> Self::T;
}
struct Producer<P>(P) where P: Produce;
fn main() {}
Unfortunately, it's tough to tell if this will work for you without knowing a lot more about the anticipated use case and code examples, which might be too verbose for Stack Overflow.