#泛型 #特质对象 #无std #擦除 #泛型 #无分配

无std dyngo

类型安全的动态(类型擦除)泛型输出参数

1个不稳定版本

0.1.0 2023年4月13日

#13#特质对象

Download history 11/week @ 2024-03-28 10/week @ 2024-04-04 1/week @ 2024-05-30 3/week @ 2024-06-06 6/week @ 2024-06-13 44/week @ 2024-06-20 15/week @ 2024-06-27

68 每月下载量

MIT/Apache

13KB
147 代码行

dyngo: 动态泛型输出参数

此crate旨在解决一个非常具体的问题:从对象安全特质返回泛型值。

// Let's say you have an object-safe interface for providing a string
trait StringProviderBad {
    fn provide(&self, f: &mut dyn FnMut(&str));
}

// You can't just return `&str`, because it can refer to a local value inside of a method:
struct TwoParts(&'static str, &'static str);

impl StringProviderBad for TwoParts {
    fn provide(&self, f: &mut dyn FnMut(&str)) {
        f(&format!("{}{}", self.0, self.1))
    }
}

// Let's try to use this interface:
fn parse_provided_string_bad<T: FromStr>(provider: &dyn StringProviderBad) -> Option<T> {
    provider.provide(&mut |s| {
        let parsed = T::from_str(s).ok();
        // But how to actually return it?
    });
    todo!()
}

// dyngo provides a type-safe solution to this problem:
trait StringProvider {
    fn provide<'id>(&self, f: &mut dyn FnMut(&str) -> Proof<'id>) -> Proof<'id>;
    //                                                ^^^^^^^^^^     ^^^^^^^^^^
    // new: now `.provide()` returns a `Proof` that `f` was called
}

// Implementation is just about the same:
impl StringProvider for TwoParts {
    fn provide<'id>(&self, f: &mut dyn FnMut(&str) -> Proof<'id>) -> Proof<'id> {
        f(&format!("{}{}", self.0, self.1))
    }
}

// And now we can use the interface to return a generic value from the provider:
fn parse_provided_string<T: FromStr>(provider: &dyn StringProvider) -> Option<T> {
    SafeSlot::with(|mut slot| {
        let proof = provider.provide(&mut |s| slot.fill(T::from_str(s).ok()));
        slot.unlock(proof)
    })
}

let num = parse_provided_string::<i32>(&TwoParts("4", "2"));
assert_eq!(num, Some(42));

注意,尝试为 Slot 使用错误的 Proof 在编译时失败:两者

SafeSlot::with(|mut slot1: SafeSlot<i32>| {
    SafeSlot::with(|mut slot2: SafeSlot<i32>| {
        let proof1 = slot1.write(42);
        slot2.unlock(proof1);
    })
})

SafeSlot::with(|mut slot1: SafeSlot<i32>| {
    SafeSlot::with(|mut slot2: SafeSlot<i32>| {
        let proof2 = slot2.write(42);
        slot1.unlock(proof2);
    })
})

无法编译。

无运行时依赖