I have this code, but it gives me a compile error. How to create an instance of the Test struct in order to fix the error?
enum Fruit {
Apple(String),
Banana(String),
}
struct Test {
A: Box<Fruit>,
}
fn main() {
let name = String::from("apple");
let test = Test {
A: Box::<Fruit::Apple("apple".to_string())>,
};
// match test {
// Box
// }
}
error: unmatched angle bracket
--> src/main.rs:13:17
|
13 | A: Box::<Fruit::Apple("apple".to_string())>,
| ^ help: remove extra angle bracket
error: expected type, found `"apple"`
--> src/main.rs:13:31
|
12 | let test = Test {
| ---- while parsing this struct
13 | A: Box::<Fruit::Apple("apple".to_string())>,
| ^^^^^^^ expected type
I think this may help you.
#[derive(Debug)]
enum Fruit {
Apple(String),
Banana(String),
}
#[derive(Debug)]
struct Test {
A: Box<Fruit>,
}
fn main() {
let test = Test {
A: Box::new(Fruit::Apple("apple".to_string())),
};
println!("{:?}", test)
}
Box<T> is the generic representation of a Box containing T. You use this when specifying the type of a value, such as a struct field or return type:
struct Test {
A: Box<Fruit>,
}
fn test() -> Box<Fruit> {}
To actually allocate memory on the heap and create a Box that stores T, you have to use the Box::new() function:
let test = Test {
A: Box::new(Fruit::Apple("apple".to_string())),
};
Related
I have two structs that depend on each other. In C++ I would do this with pointers, I'm trying to figure out how to do this in Rust. I've tried using Box and Rc so far, I would think since Rc is a reference counter it should be able to handle this, but it's giving me an error.
Here is a simple code example:
struct A {
b : Rc<B>
}
struct B {
a : Option<Rc<A>>
}
fn main() {
let mut b = B {
a : None
};
let a = A {
b: Rc::new(b)
};
b.a = Some(Rc::new(a));
}
Here is the error I get from it:
20 | let mut b = B {
| ----- move occurs because `b` has type `B`, which does not implement the `Copy` trait
...
25 | b: Rc::new(b)
| - value moved here
...
28 | b.a = Some(Rc::new(a));
| ^^^ value partially assigned here after move
What is the correct way to do this type of relationship in Rust?
You shouldn't use Rc::new twice for an object. The correct way is to use Rc::new once, and clone it as needed. What's more, in order to mutate b behind a Rc, you should combine it with RefCell.
use std::cell::RefCell;
use std::rc::Rc;
struct A {
b: Rc<B>,
}
struct B {
a: RefCell<Option<Rc<A>>>,
}
fn main() {
let b = Rc::new(B {
a: RefCell::new(None),
});
let a = Rc::new(A { b: b.clone() });
*b.a.borrow_mut() = Some(a.clone());
assert!(b.a.borrow().is_some());
}
But even you do like this, you still make an memory leak, which is bad. A better way is to use Weak and Rc::new_cyclic to make cycles.
use std::rc::{Rc, Weak};
struct A {
b: Rc<B>,
}
struct B {
a: Weak<A>,
}
fn main() {
let a: Rc<A> = Rc::new_cyclic(|a| A {
b: Rc::new(B { a: a.clone() }),
});
let b: Rc<B> = a.b.clone();
}
This avoids use of cells and memory leak.
This is compiling (this is single threaded example)
use std::cell::RefCell;
use std::rc::Rc;
// make a cycle: struct A owning struct B and struct B owning struct A
struct A {
b : Rc<RefCell<B>>
}
struct B {
a : Option<Rc<RefCell<A>>>
}
fn main() {
// init b with None
let b = Rc::new(RefCell::new(B { a: None }));
// init a with b
let a = Rc::new(RefCell::new(A { b: Rc::clone(&b) }));
// set b.a to a
b.borrow_mut().a = Some(Rc::clone(&a));
}
You use Rc to have mutiple ownership. So that you can both move b to a and then still address it as b and even try change it.
Rc is read only so use RefCell so that you hide the fact that you change things.
There is another example of cycle in Rust book
https://doc.rust-lang.org/book/ch15-06-reference-cycles.html
I'm trying to do this, but it doesn't work:
struct Pack {
data: Box<[u8]>
}
fn foo() {
let mut p = Pack {
data: Box::new(**b"Hello!")
};
p.data.set(b"Bye!");
}
I'm getting:
error[E0614]: type `[u8; 6]` cannot be dereferenced
--> foo
|
30 | data: Box::new(**b"Hello!")
| ^^^^^^^^^^^
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
--> foo
|
30 | data: Box::new(**b"Hello!")
| ^^^^^^^^ doesn't have a size known at compile-time
|
What is the right way to do this?
Just use a Vec instead:
struct Pack {
data: Vec<u8>
}
fn foo() {
let mut p = Pack {
data: b"Hello!".to_vec()
};
p.data=b"Bye!".to_vec();
}
A vector is just like a array, except it's size is dynamic and you can resize it at runtime. See the docs for more details.
I wrote such a macro with a test example like this:
#[selector]
pub enum Action {
A = "a()",
B = "b()",
}
The selector implementation:
#[proc_macro_attribute]
pub fn selector(attr: TokenStream, item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as ItemEnum);
let ItemEnum { attrs, vis, enum_token, ident, variants, .. } = input;
let mut ident_vec: Vec<Ident> = Vec::new();
let mut hash_vec: Vec<Expr> = Vec::new();
let mut count = 0u32;
for variant in variants {
count = count + 1;
if let Some((_, Expr::Lit(lit))) = variant.discriminant {
let ExprLit { attrs, lit } = lit;
if let Lit::Str(lit_str) = lit {
ident_vec.push(variant.ident);
hash_vec.push(Expr::Lit(ExprLit {
attrs: Default::default(),
// lit: Lit::Verbatim(Literal::u32_unsuffixed(count)), // works
lit: Lit::Verbatim(Literal::u32_suffixed(count)), // compile error
}));
}
}
}
(quote! {
#vis #enum_token #ident {
#(
#ident_vec = #hash_vec
),*
}
})
.into()
}
The compile error report:
error[E0308]: mismatched types
--> macros/generate-actions/tests/tests.rs:6:2
|
6 | #[generate_actions::selector]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| expected `isize`, found `u32`
| in this procedural macro expansion
|
::: /home/bear/working/darwinia/play-rust/macros/generate-actions/src/lib.rs:8:1
|
8 | pub fn selector(attr: TokenStream, item: TokenStream) -> TokenStream {
| -------------------------------------------------------------------- in this expansion of `#[generate_actions::selector]`
|
help: change the type of the numeric literal from `u32` to `isize`
|
6 | #[generate_actions::selector]isize
I want to know why u32_suffixed will trigger such a compile error?
The problem here has nothing to do with the fact that you're using a macro. The issue is that the macro generates code similar to this:
enum Foo {
A = 0u32,
}
Playground
Which triggers the same error. However according to the Rust reference, enum discriminants are supposed to have type isize:
enum Foo {
A = 0, // Automatically inferred as `isize`
B = 1isize, // OK
}
Playground
I'm trying to program an assembler for an as-of-yet unimplemented processor architecture using Rust. I just finished the lexer and am trying to build it and fix any typos and errors I have made along the way.
However, one error that keeps clogging the build log is error E0308: mismatched types. Essentially, every time I try to return a Result::Err (because the source file contained an error) somewhere the rust compiler isn't expecting me to, I get this error. I do not care what the rust compiler expects. I'm trying to write an assembler here. What can I do to stop E0308 from occurring?
Example: Here's a bit of my program where this error was triggered.
if bin_regex.is_match(&s[1..25]) {
// Absolute Memory
add_info = AddressInfo::new(ValueType::Binary, AddressMode::AbsoluteMemory);
content = &s[0..25];
} else if bin_regex.is_match(&s[1..17]) {
if &s[17..18] == "p" {
// Absolute Port
add_info = AddressInfo::new(ValueType::Binary, AddressMode::AbsolutePort);
content = &s[0..18];
} else {
// Zero Bank
add_info = AddressInfo:new(ValueType::Binary, AddressMode::ZeroBank);
content = &s[0..17];
} else if bin_regex.is_match(&s[1..9]) {
// Zero Page
add_info = AddressInfo::new(ValueType::Hexadecimal, AddressMode::ZeroPage);
content = &s[0..9];
} else {
// Error
Err(format!("Invalid Binary address or Binary address out of range"))
}
And here's what the error looks like:
...
error[E0308]: mismatched types
--> src/lex.rs:407:17
|
401 | } else if bin_regex.is_match(&s[1..9]) {
| ____________________-
402 | | // Zero Page
403 | | add_info = AddressInfo::new(ValueType::Binary, AddressMode::ZeroPage);
404 | | content = &s[0..9];
... | |
407 | | Err(format!("Invalid Binary address or Binary address out of range"))
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found enum `std::result::Result`
408 | | }
| |_____________- expected this to be `()`
|
= note: expected unit type `()`
found enum `std::result::Result<_, std::string::String>`
...
Errors aren't special in Rust. If you wish to return an error from a function, that function must have the Result return type. Suppose we have this function:
fn divide(a: i64, b: i64) -> i64 {
a / b
}
But there's a problem in case b == 0, so we'd like to report an error instead:
fn divide(a: i64, b: i64) -> i64 {
if b == 0 {
Err("divide by zero")
} else {
a / b
}
}
But this runs into your error:
error[E0308]: mismatched types
--> src/main.rs:3:13
|
1 | fn divide(a: i64, b: i64) -> i64 {
| --- expected `i64` because of return type
2 | if b == 0 {
3 | Err("divide by zero")
| ^^^^^^^^^^^^^^^^^^^^^ expected `i64`, found enum `std::result::Result`
|
= note: expected type `i64`
found enum `std::result::Result<_, &str>`
What we must do is give the function the appropriate type, that allows us to return results that can have errors. We must also wrap any result that isn't an error in Ok(...):
fn divide(a: i64, b: i64) -> Result<i64, &'static str> {
if b == 0 {
Err("divide by zero")
} else {
Ok(a / b)
}
}
Note that it's not a good practice to use raw strings as error types - this is just for a quick example.
If you just want your application to exit when your error case occurs, then you should use panic! rather than Err(...) (as Err is a constructor that just creates a Result object and does nothing with it)
pub fn doit() {
if ... {
// ...
} else {
// Error
panic!("Invalid Binary address or Binary address out of range"))
}
}
Generally using panic! is frowned upon to some degree. But for initial work, it is often OK. Later you may want to change the function to return a Result so you can do better error handling. In that case you return an Err.
pub fn doit() -> Result<(), String> {
if ... {
// ...
} else {
// Error
return Err(format!("Invalid Binary address or Binary address out of range"));
}
Ok(())
}
The next step is to use a specific error type to encode the errors
#[derive(Debug, Clone)]
pub enum Error {
InvalidAddressError,
...
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Invalid Binary address or Binary address out of range")
}
}
pub fn doit() -> Result<(), Error> {
if ... {
// ...
} else {
// Error
return Err(Error::InvalidAddressError);
}
Ok(())
}
The following code works:
pub struct Bar {
pub name: String
}
macro_rules! printme {
($myclass: ident) => {
let t = $myclass { name: "abc".to_owned() };
println!("{}", t.name);
}
}
fn main() {
printme!(Bar);
}
However, if Bar is within a module, it won't work, error is no rules expected the token :::
mod foo {
pub struct Bar {
pub name: String
}
}
macro_rules! printme {
($myclass: ident) => {
let t = $myclass { name: "abc".to_owned() };
println!("{}", t.name);
}
}
fn main() {
printme!(foo::Bar); // not allowed
}
It only works if I use an alias:
fn main() {
use foo::Bar as no_colon;
printme!(no_colon);
}
Is there a way to make it work with the colon, without the use alias?
When you write ($myclass: ident) you are saying that the user must write an identifier in that place of the macro invocation. And as you noted, Bar is an identifier, but foo::Bar is not: syntactically, this kind of list-of-identifiers-separated-by-double-colon is called a path.
You can write ($myclass: path), or if you want to limit that to existing types then you can write ($myclass: ty), as #phimuemue's answer suggested. But if you do this, it will fail when trying to use that type to build the object. That is because of how the parser work: it must parse the path and the { in the same token tree, but having the path or ty has broken the link with the {. Since this is just a parser limitation, not a semantic one, you can use a local alias as a workaround, as the other answer suggests.
However, I would suggest to use a trait based solution if possible. I consider that to me much more idiomatic:
trait Nameable {
fn new(name: &str) -> Self;
}
mod foo {
pub struct Bar {
pub name: String
}
impl super::Nameable for Bar {
fn new(name: &str) -> Bar {
Bar {
name: name.to_string()
}
}
}
}
macro_rules! printme {
($myclass: ty) => {
let t = <$myclass as Nameable>::new("abc");
println!("{}", t.name);
}
}
fn main() {
printme!( foo::Bar );
}
Or you can take out the ultimate tool of Rust macros: the list-of-token-trees, that can parse almost anything:
macro_rules! printme {
($($myclass: tt)*) => {
let t = $($myclass)* { name: "abc".to_string() };
println!("{}", t.name);
}
}
When you invoke this macro with printme!(foo::Bar) it will actually parse as a list of three token-trees: foo, :: and Bar, and then your building of the object will just work.
The drawback (or advantage) of this method is that it will eat up all your tokens, no matter what you write into the macro, and if it fails it will emit a weird error message from inside your macro, instead of saying that your token is not valid in this macro invocation.
For example, writing printme!( foo::Bar {} ) with my trait-based macro gives the most helpful error:
error: no rules expected the token `{`
--> src/main.rs:27:24
|
19 | macro_rules! printme {
| -------------------- when calling this macro
...
27 | printme!( foo::Bar {} );
| ^ no rules expected this token in macro call
While writing the same code with the token-tree-list macro produces a few not so helpful messages:
warning: expected `;`, found `{`
--> src/main.rs:21:30
|
21 | let t = $($myclass)* { name: "abc".to_string() };
| ^
...
27 | printme!( foo::Bar {} );
| ------------------------ in this macro invocation
|
= note: this was erroneously allowed and will become a hard error in a future release
error: expected type, found `"abc"`
--> src/main.rs:21:38
|
21 | let t = $($myclass)* { name: "abc".to_string() };
| - ^^^^^ expected type
| |
| tried to parse a type due to this
...
27 | printme!( foo::Bar {} );
| ------------------------ in this macro invocation
error[E0063]: missing field `name` in initializer of `foo::Bar`
--> src/main.rs:27:15
|
27 | printme!( foo::Bar {} );
| ^^^^^^^^ missing `name`
With a little trickery you can make it work:
mod foo {
pub struct Bar {
pub name: String
}
}
macro_rules! printme {
($myclass: ty) => {
type LocalT = $myclass;
let t = LocalT { name: "abc".to_owned() };
println!("{}", t.name);
}
}
fn main() {
printme!(foo::Bar);
}
accept ty (type) instead of ident (identifier)
I do not know why, but I couldn't get it working without LocalT