Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I have to explicitly cast to a constrained type?

Tags:

rust

Why doesn't the commented-out bar code below compile, even though foo and baz do?

use std::any::Any;
use std::fmt::Display;

// `value` implements `Clone`, so I can call `.clone()`.
fn foo<T: Display + Clone>(value: &T) {
    println!("{}", value.clone());
}

// `value` implements `Any`, so I should be able to call `.downcast_ref`...
// But this doesn't compile!
//
// fn bar<T: Display + Any>(value: &T) {
//     println!("{}", value.downcast_ref::<i32>());
// }

// For some reason I have to do an explicit cast to `&Any`...
fn baz<T: Display + Any>(value: &T) {
    let value = value as &Any;
    println!("{}", value.downcast_ref::<i32>().unwrap());
}

fn main() {
    foo(&7);
    // bar(&8);
    baz(&9);
}

Trying to compile bar yields the following compiler error:

error[E0599]: no method named `downcast_ref` found for type `&T` in the current scope
  --> src/main.rs:13:30
   |
13 |         println!("{}", value.downcast_ref::<i32>());
   |                              ^^^^^^^^^^^^

I already spelled out the constraint that value must implement Any so why do I have to do an explicit cast?

like image 713
Josh Burkart Avatar asked Sep 05 '17 00:09

Josh Burkart


1 Answers

That's because downcast_ref is not part of the trait itself. If we look at the trait's definition in the documentation:

pub trait Any: 'static {
    fn get_type_id(&self) -> TypeId;
}

we can see that downcast_ref is not there. Only methods defined as members of a trait are made available on types that implements that trait.

Rather, downcast_ref is in an impl Any + 'static block1. Since the method takes &self, it means the method is only available on values of type &(Any + 'static) (&Any with no lifetime specified is equivalent to &(Any + 'static)). &Any and &T (where T is a type parameter) are not the same type; &Any is a trait object (which is a fat pointer), while &T is just a normal reference (which is a thin pointer).


1 It's also defined in an impl Any + 'static + Send block, so the method is also available on values of type &(Any + 'static + Send).

like image 166
Francis Gagné Avatar answered Nov 16 '22 04:11

Francis Gagné