Faced a weird case of repeated argument mismatch while creating a macro in Rust:
use std::mem;
trait Object {}
#[derive(Debug)]
struct This {}
impl Object for This {}
#[derive(Debug)]
struct That {}
impl Object for That {}
macro_rules! types {
($($fname:ident),*) => {
enum Type {
$($fname),*
}
fn match_it(t: Type, b: Box<Object>) {
let p = match t {
$(
Type::$fname => {
mem::transmute::<Box<Object>, Box<$fname>>(b)
}
),*
};
}
}
}
types!(This, That);
fn main() {}
It results in:
error: match arms have incompatible types [--explain E0308]
--> <anon>:20:21
20 |> let p = match t {
|> ^ expected struct `This`, found struct `That`
<anon>:31:1: 31:20: note: in this expansion of types! (defined in <anon>)
note: expected type `Box<This>`
note: found type `Box<That>`
note: match arm with an incompatible type
--> <anon>:22:33
22 |> Type::$fname => {
|> ^
<anon>:31:1: 31:20: note: in this expansion of types! (defined in <anon>)
Shouldn't the $fname of enum be the same as $fname of Box if they share the same loop?
Play it.
The macro expands to something like:
enum Type {This, That }
fn match_it(t: Type, b: Box<Object>) {
let p = match t {
Type::This => mem::transmute::<Box<Object>, Box<This>>(b),
Type::That => mem::transmute::<Box<Object>, Box<That>>(b),
}
}
What's the type of p? Depending on something at runtime, the compile-time type must be different; this doesn't make sense in a statically typed language like Rust.
I suggest looking into std::any, which seems similar to what you might be trying to do.
As an alternative, maybe you want runtime casting using Box<Any>:
use std::any::Any;
struct N(isize);
struct S(String);
fn main() {
let mut v: Vec<Box<Any>> = Vec::new();
v.push(Box::new(N(17)));
v.push(Box::new(S("foo".to_string())));
let s = v.pop().unwrap().downcast::<S>().unwrap();
let n = v.pop().unwrap().downcast::<N>().unwrap();
println!("Extracted {} and {}", s.0, n.0);
}
Play link
Related
Assuming the following code is present
use core::any::Any;
enum Value {
Any(Box<dyn Any>),
Other, // placeholder, this code is adapted from mine
}
This code raises a diagnostic that I can't quite understand
impl<T: Any> TryFrom<Value> for T {
type Error = &'static str;
fn try_from(val: Value) -> Result<Self, Self::Error> {
if let Value::Any(any) = val {
if let Ok(down) = any.downcast::<T>() {
Ok(*down)
} else {
Err("incorrect type")
}
} else { Err("not an any") }
}
}
fn main() {
let res: Result<usize, &'static str> = Value::Any(Box::new(1usize)).try_into();
dbg!(res);
}
error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Value`)
--> src/main.rs:9:6
|
9 | impl<T: Any> TryFrom<Value> for T {
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`Value`)
|
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
I still don't quite understand what "must be covered by another type" means, nor "when it appears before the first local type".
However, if I modify the impl signature to target a single-element tuple containing T, the impl does not raise an error, and the code functions correctly:
impl<T: Any> TryFrom<Value> for (T,) {
type Error = &'static str;
fn try_from(val: Value) -> Result<Self, Self::Error> {
if let Value::Any(any) = val {
if let Ok(down) = any.downcast::<T>() {
Ok((*down,))
} else {
Err("incorrect type")
}
} else { Err("not an any") }
}
}
fn main() {
let res: Result<(usize,), &'static str> = Value::Any(Box::new(1usize)).try_into();
dbg!(res);
}
What purpose does the single-element tuple actually serve?
(Playground Link)
From RFC 2451:
Covered Type: A type which appears as a parameter to another type. For example, T is uncovered, but the T in Vec<T> is covered. This is only relevant for type parameters.
It is important to note that the type T does not equal the tuple type (T,). (T,) can be considered equivalent to a hypothetical generic newtype/tuple struct struct Tuple1<T>(T) defined in the standard library crate std. With this analogy, impl<T: Any> TryFrom<Value> for (T,) is equivalent to impl<T: Any> TryFrom<Value> for std::Tuple1<T>.
Note that the covering type (in this case the single element tuple type, or in our analogy Tuple1) need not be defined locally in the same crate. To put it simply, consider an impl<T> ForeignTrait<LocalType> for ForeignType<T>:
The covering type ForeignType has already been defined. So:
The only way ForeignTrait<LocalType> can be implemented for
ForeignType<T> outside of the current crate is through a generic
impl <S, T> ForeignTrait<S> for ForeignType<T> (where S covers
LocalType).
Because of these rules, an impl <S, T> ForeignTrait<S> for ForeignType<T> that covers ForeignTrait<LocalType> is only possible in the crate declaring ForeignType.
Hence it is impossible for a conflicting implementation of ForeignTrait<LocalType> to exist for ForeignType<T> outside of a) the local crate and b) the crate declaring ForeignType, and so the impl is allowed. The RFC discusses this in more detail.
How does the the <From> trait know which type to convert to in different contexts if it's implemented for more than one type?
For example, i have three types that have some mutual conversions implemented. On Character i implement From for both Token and AminoAcid. Yet, when i call .into() in the hashmap i don't have to specify which type is required by the map's type definition. How is the trait aware of the context?
#[derive(Debug)]
struct Coordinate{
x:f64, y:f64, z:f64
}
#[derive(Debug)]
enum AminoAcid {
VAL, GLN ,ARG,...
}
#[derive(Debug)]
enum Token {
Coordinate(Coordinate),
AminoAcid(AminoAcid),
Character(Character)
}
impl From<Coordinate> for Token {
fn from(coord: Coordinate) -> Self {
Self::Coordinate(coord)
}
}
impl From<AminoAcid> for Token {
fn from(aa: AminoAcid) -> Self {
Self::AminoAcid(aa)
}
}
// ------------------------------------------------- <<<<
impl From<Character> for Token {
fn from(c: Character) -> Self {
Self::Character(c)
}
}
impl From<Character> for AminoAcid {
fn from(c: Character) -> Self {
Self::ALA
}
}
// ------------------------------------------------- <<<<
lazy_static! {
static ref HASHMAP: HashMap<&'static str, Token> = { // Here the value type is Token
let mut m = HashMap::new();
m.insert("ALA", Character::Second.into());
m
};
static ref HASHMAP: HashMap<&'static str, AminoAcid> = { // Here the value type is AminoAcid
let mut m = HashMap::new();
m.insert("ALA", Character::Second.into());
m
};
}
It's because Rust can deduce/infer types.
For example
fn f1(arg: u8) {
println!("u8 in f1: {}", arg)
}
fn f2(arg: i64) {
println!("i64 in f2: {}", arg)
}
fn main() {
let a = 12;
let b = 23;
f1(a);
f2(b);
// f1(b); // expected `u8`, found `i64`
// f2(a); // expected `i64`, found `u8`
}
a and b are declared the same way; at this point, the compiler just knows they are some kind of integer.
At the first call of f1(), since the expected argument is an u8, Rust deduces that a is actually an u8.
The same goes for b deduced as an i64 at the first usage of f2().
Of course, if after that we try to make the compiler deduce other types for these variables, it fails.
In your case, you declare your static bindings as hashmaps of a specific type: Token in one case, AminoAcid in the other.
Then, the brace used to initialise such a binding have to match this type; the type of the resulting expression (m) is deduced accordingly.
The way we initialise m expects the correct value type.
Consequently, the version of into() providing this type is chosen.
Because you defined the type of HASHMAP, the compiler infers which type is needed, since if it converted into the other type it would not compile. https://doc.rust-lang.org/rust-by-example/types/inference.html
I have the following enum defined:
#[derive(Debug, Copy, Clone)]
struct Core;
#[derive(Debug, Copy, Clone)]
struct Mem;
#[derive(Debug, Copy, Clone)]
pub enum Atag {
Core(Core),
Mem(Mem),
Cmd(&'static str),
Unknown(u32),
None,
}
I would like to implement a function on this enum which "filters out" certain enum values. I have the following:
impl Atag {
/// Returns `Some` if this is a `Core` ATAG. Otherwise returns `None`.
pub fn core(self) -> Option<Core> {
match self {
Atag::Core => Some(self),
_ => None
}
}
}
I'm not sure why, but the compiler complains:
error[E0532]: expected unit struct/variant or constant, found tuple variant `Atag::Core`
--> src/main.rs:17:13
|
17 | Atag::Core => Some(self),
| ^^^^^^^^^^ not a unit struct/variant or constant
help: possible better candidate is found in another module, you can import it into scope
|
1 | use Core;
|
I also tried a comparison approach:
pub fn core(self) -> Option<Core> {
if self == Atag::Core {
Some(self)
} else {
None
}
}
But the compiler complains:
error[E0369]: binary operation `==` cannot be applied to type `Atag`
--> src/main.rs:20:12
|
20 | if self == Atag::Core {
| ^^^^^^^^^^^^^^^^^^
|
= note: an implementation of `std::cmp::PartialEq` might be missing for `Atag`
I think this is just a limitation of the pattern matching and is designed to prevent unexpected behavior.
The full "definition" of an Atag with type Core is Atag::Core(raw::Core). Obviously, the contents of the Core are irrelevant to you, but the compiler needs to know that everything is "accounted for" because the compiler is a stickler for the rules. The easiest way to get around this is to use the "anything pattern", _, much like you did to match non-Core variants.
impl Atag {
/// Returns `Some` if this is a `Core` ATAG. Otherwise returns `None`.
pub fn core(self) -> Option<Core> {
match self {
// The compiler now knows that a value is expected,
// but isn't necessary for the purposes of our program.
Atag::Core(_) => Some(self),
_ => None
}
}
}
To ignore multiple values, you'd use Something::Foo(_, _) - one underscore for each value in the variant, or Something::Foo(..) to ignore everything.
Remember that, unlike in some other languages, a Rust enum is not "just" a collection of different types. Data associated with an enum value is a part of it, just like the fields of a structure. So self == Atag::Core isn't a meaningful statement because it ignores the data associated with a Core. A Foo(0) is different than a Foo(12), even if they're both of the Foo variant.
I'd also like to point out if let, which is - as far as I can tell - the closest option to a standard if statement without defining a custom is_core function on Atag (which, given the existence of match and if let, is basically unnecessary).
impl Atag {
/// Returns `Some` if this is a `Core` ATAG. Otherwise returns `None`.
pub fn core(self) -> Option<Core> {
if let Atag::Core(_) = self {
Some(self)
} else {
None
}
}
}
I needed something like this to chain functions together nicely. In that case, you want to return the unwrapped core type, rather than just the enum.
I also found it easier to not consume the input, and so accepted a &self argument an returned an Option<&Core>. But you can have both.
The Rust convention has as_X as the reference-based conversion and into_X as the conversion that consumes the value. For example:
impl Atag {
fn as_core(&self) -> Option<&Core> {
if let Atag::Core(ref v) = self {
Some(v)
} else {
None
}
}
fn into_core(self) -> Option<Core> {
if let Atag::Core(v) = self {
Some(v)
} else {
None
}
}
}
fn main() {
let c = Atag::Core(Core {});
let m = Atag::Mem(Mem {});
assert_eq!(c.as_core().map(|cc| "CORE_REF"), Some("CORE_REF"));
assert_eq!(m.as_core().map(|cc| "CORE_REF"), None);
// Consume c - we cant use it after here...
assert_eq!(c.into_core().map(|cc| "NOM NOM CORE"), Some("NOM NOM CORE"));
// Consume m - we cant use it after here...
assert_eq!(m.into_core().map(|cc| "NOM NOM CORE"), None);
}
The docs for Arc<T> say:
Arc<T> automatically dereferences to T (via the Deref trait), so you can call T's methods on a value of type Arc<T>.
But is there any way to allow for matching on Option-al types?
Here is a simple example:
use std::sync::Arc;
fn main() {
let foo: Arc<Option<String>> = Arc::new(Some("hello".to_string()));
if foo.is_some() {
println!("{}", foo.unwrap());
}
match foo {
Some(hello) => {
println!("{}", hello);
}
None => {}
}
}
The compiler error is:
error[E0308]: mismatched types
--> src/main.rs:11:9
|
11 | Some(hello) => {
| ^^^^^^^^^^^ expected struct `std::sync::Arc`, found enum `std::option::Option`
|
= note: expected type `std::sync::Arc<std::option::Option<std::string::String>>`
found type `std::option::Option<_>`
error[E0308]: mismatched types
--> src/main.rs:14:9
|
14 | None => {}
| ^^^^ expected struct `std::sync::Arc`, found enum `std::option::Option`
|
= note: expected type `std::sync::Arc<std::option::Option<std::string::String>>`
found type `std::option::Option<_>`
No, you cannot match on an Option inside of an Arc. To use a type in pattern matching, the implementation of the type must be available to you, but the implementation of Arc is not public.
In certain cases, you can perform some kind of conversion to be able to match on a reference.
For example, since Arc<T> implements Deref, you can use the * operator to dereference through the Arc<T> to the underlying T. Since there's some ergonomic syntax for this kind of matching, you can then take a reference to the value inside the Option without taking ownership of it:
match *foo {
Some(ref hello) => {
println!("{}", hello);
}
None => {}
}
You can also use Option::as_ref to convert the &Option<T> (automatically dereferenced from the Arc<T> via Deref) to an Option<&T>:
match Option::as_ref(&foo) {
Some(hello) => {
println!("{}", hello);
}
None => {}
}
Unfortunately, you can't just call .as_ref() because the trait method AsRef::as_ref takes precedence.
In both cases, it's more idiomatic to use if let if you only care about one of the match arms:
if let Some(ref hello) = *foo {
println!("{}", hello);
}
The first println passed the early stages of the compiler, but it got flagged by the borrow checker in a later stage. The second println was an easier fix.
use std::sync::Arc;
fn main() {
let foo: Arc<Option<String>> = Arc::new(Some("hello".to_string()));
if foo.is_some() {
let f1: &Option<String> = foo.as_ref();
let f2: Option<&String> = f1.as_ref();
let f3: &String = f2.unwrap();
println!("{}", f3);
println!("{}", foo.as_ref().as_ref().unwrap())
}
match *foo {
Some(ref hello) => {
println!("{}", hello);
}
None => {}
}
}
The first println confusingly uses two as_ref() method calls. The first as_ref acts on the Arc, with type signature Fn(&Arc<Option<String>>) -> &Option<String>. The second one acts on the Option, with type signature Fn(&Option<String>) -> Option<&String>
playground
struct Plugin;
struct Blueprint<'a>(&'a ());
struct Shell<'a> {
plugins: Vec<(&'a Plugin, Vec<Blueprint<'a>>)>,
}
impl<'a> Shell<'a> {
fn find_blueprint(&self, name: &str) -> Option<Blueprint> {
for plugin_blueprints in self.plugins.as_ref() {
for blueprint in plugin_blueprints.1 {
if blueprint.name.to_string() == name {
return Some(blueprint);
}
}
}
None
}
}
fn main() {}
Generates this error:
error: the type of this value must be known in this context
--> src/main.rs:11:30
|
11 | for blueprint in plugin_blueprints.1 {
| ^^^^^^^^^^^^^^^^^^^
This confuses me because plugin_blueprints seems to be unambiguously of type (&'a Plugin, Vec<Blueprint<'a>>). I'm not sure what syntax (if any) I would use to specify the type in a for-loop. Turbo-fish ::< doesn't seem to work.
Because you are using as_ref, which is more generic than you want. The value of T cannot be inferred:
pub trait AsRef<T>
where T: ?Sized
{
fn as_ref(&self) -> &T;
}
The idiomatic way to iterate over this is
for plugin_blueprints in &self.plugins {}
The pretty nasty way of doing it is to use the turbofish on the trait, using the disambiguated function call syntax:
for plugin_blueprints in AsRef::<[(&'a Plugin, Vec<Blueprint<'a>>)]>::as_ref(&self.plugins) {
Your function will actually return a Option<&Blueprint> because you start with &self. You should also use self.plugins.iter() and plugin_blueprints.1.iter() to stop the ambiguity introduced by as_ref() and fix your lifetimes.
See here