1 个不稳定版本

0.2.0 2019年6月18日

#42 in #sized


用于 traitcast

MIT 许可证

15KB
217

traitcast

Any 转换

在标准库中,std::any::Any 特质包含 downcast 方法,允许您将 Any 特质对象转换为具体类型。

let x: i32 = 7;
let y: &dyn std::any::Any = &x;

// Cast to i32 succeeds because x: i32
assert_eq!(y.downcast_ref::<i32>(), Some(&7));
// Cast to f32 fails
assert_eq!(y.downcast_ref::<f32>(), None);

但是,无法将转换为目标特质对象。

trait Foo {
    fn foo(&self) -> i32;
}

struct A {
    x: i32
}

impl Foo for A {
    fn foo(&self) -> i32 {
        self.x
    }
}

let x = A { x: 7 };
let y: &dyn std::any::Any = &x;

// This cast is not possible, because it is only possible to cast to types that
// are Sized. Among other things, this precludes trait objects.
let z: Option<&dyn Foo> = y.downcast_ref();

traitcast

此库提供了一种在不同特质对象之间进行转换的方法。

use traitcast::{TraitcastFrom, Traitcast};

// Extending `TraitcastFrom` is optional. This allows `Foo` objects themselves
// to be cast to other trait objects. If you do not extend `TraitcastFrom`,
// then Foo may only be cast into, not out of.
trait Foo: TraitcastFrom {
    fn foo(&self) -> i32;
}

trait Bar: TraitcastFrom {
    fn bar(&mut self) -> i32;
}

struct A {
    x: i32
}

// No implementation of TraitcastFrom is necessary, because it is covered by
// the blanket impl for any sized type with a static lifetime.
impl Foo for A {
    fn foo(&self) -> i32 {
        self.x
    }
}

impl Bar for A {
    fn bar(&mut self) -> i32 {
        self.x *= 2;
        self.x
    }
}

// Register the traits.

// For each struct that implements each trait, register the implementation.
traitcast::traitcast!(struct A: Foo, Bar);

fn main() {
    let mut x = A { x: 7 };

    {
        let x: &dyn Foo = &x;
        // Test whether x is of a type that implements Bar.
        assert!(traitcast::implements_trait::<dyn Foo, dyn Bar>(x));
    }

    {
        let x: &dyn Bar = &x;
        // Cast an immutable reference using the `cast_ref` method (via the
        // `Traitcast` trait, which is blanket implemented for all pairs of
        // traits that may be cast between).
        let x: &dyn Foo = x.cast_ref().unwrap();
        assert_eq!(x.foo(), 7);

        // We can also cast using the top-level `cast_ref` function, which can
        // be more convenient when type arguments cannot be inferred.
        assert!(traitcast::cast_ref::<dyn Foo, dyn Bar>(x).is_some());
    }

    {
        let x: &mut dyn Foo = &mut x;
        // Cast a mutable reference using the `cast_mut` method
        let x: &mut dyn Bar = x.cast_mut().unwrap();
        assert_eq!(x.bar(), 14);
    }

    {
        // We can cast from `Any` too!
        let y: Box<dyn std::any::Any> = Box::new(x);
        // Cast a boxed reference
        let z: Box<dyn Foo> = y.cast_box().unwrap();
        assert_eq!(z.foo(), 14);
    }
}

lib.rs:

此模块是 traitcast 的一般接口,不依赖于全局注册表。这使得它更加灵活,但代价是必须创建注册表并在周围传递。如果您不希望这样做,请使用根 traitcast 模块,它提供了一个方便的全局注册表。

依赖项

~40–265KB