gpt4 book ai didi

rust - 实现伪裸约束

转载 作者:行者123 更新时间:2023-12-03 09:38:17 24 4
gpt4 key购买 nike

我正在努力清除 Rust 中的依赖注入(inject)(DI)。我有一些工作,但我正在努力让它变得更好。据我了解,Rust 可以 不是 支持带有类型参数的裸约束(就像其他一些语言一样)。我正在尝试确定是否有可能以不安全的方式伪造裸约束(假设这是必要的)。对于不正确的映射,我完全可以接受史诗般的失败。我对 Rust 的理解很简单,我需要说服它 T确实实现了U并且可以隐式或显式地转换为它。通过强制转换,我的意思是可以将具体但通用的类型强制转换为特征对象,因为它实现了它(我意识到大多数人要求另一个方向,我理解那里的复杂性)。
包括我所拥有的一切都会有点多;但是,这里有一些上下文。考虑我们可以将工厂函数归结为(这可行):

Rc<dyn Fn(&ServiceProvider) -> Rc<dyn Any>>
目前,我有一个看起来像(删节)的构建器:
pub struct ServiceDescriptorBuilder<TSvc: Any + ?Sized, TImpl> {
_phantom_svc: PhantomData<TSvc>,
_phantom_impl: PhantomData<TImpl>,
}

impl<TSvc: Any + ?Sized, TImpl> ServiceDescriptorBuilder<TSvc, TImpl> {
pub fn from<F>(self, factory: F) -> ServiceDescriptor
where
F: Fn(&ServiceProvider) -> Rc<TSvc> + 'static, {
// convert to factory
let factory = Rc::new(move |sp| Rc::new(factory(sp)));
}
}
这完全适用于:
let descriptor = ServiceDescriptorBuilder::<dyn Foo, FooImpl>::new(/* unimportant */)
.from(|sp| Rc::new(FooImpl::default()))
我的目标是删除额外的 Rc在工厂关闭声明。 全部 实例包含在 Rc 中.短暂的生命周期总能得到新鲜的 Rc计数为 1,而单例具有克隆的 Rc .我想要做的是(例如减去 Rc ):
let descriptor = ServiceDescriptorBuilder::<dyn Foo, FooImpl>::new(/* unimportant */)
.from(|sp| FooImpl::default())
我可以获得第二个更简单的变体来编译,但它在运行时失败 - 原因很明显。我需要说服 Rust 使用 Rc<dyn Foo>拥有值 FooImpl .这对于泛型来说似乎是不可能的。关联类型也许可以,但这只是一种选择,如果它仍然产生简洁的语法。真正让我感到困惑的是编译器本身可以做的魔法。理解 Rc<FooImpl>似乎没有问题是协变的并且可以满足 Rc<dyn Foo> .
我有一些工作,所以这并不是真正的阻塞,但让我很恼火的是,这不能以更简单的形式实现。也许这只是语言的当前限制。其他一些语言允许将其表示为 where TImpl: TSvc .我不会假装理解为什么这很难或尚不支持,但其他语言已经弄清楚了。我知道已经有一个限制,您不能将类型限制为特征。也许这是使这更简洁所需的唯一功能。
我满足于等待,但似乎有一些不安全的方法可以制作 Rc拥有 FooImpl 的实例, 但表示为 Rc<dyn Foo> .除非我有严重的误解,否则这就是编译器最终产生的结果。我不清楚如何强制或复制它。
我对使用宏来解决这个问题并不感到兴奋,但我认为这是一个可以接受的解决方案;特别是,如果它可以作为实现细节隐藏起来(来自调用者/开发者)。虽然我当前的解决方案确实有效并且更加冗长,但它确实提供了某种程度的编译器检查,因为您不能只返回任何内容。删除此检查的更简洁的语法(使用 transmute 或其他东西)可能不值得权衡。
建议?

最佳答案

如果我总结正确,您基本上想从具体类型 FooImpl到特征对象 dyn Foo但在一般设置中(在这种情况下通过 Rc )。

use std::rc::Rc;

fn to_dyn<DynTrait, Impl>(i: Rc<Impl>) -> Rc<DynTrait> {
// ... some implementation
}
在稳定的 Rust 中没有现有的约束可以做到这一点。您必须手动实现 ToDyn 之类的东西您要使用的每种类型的特征;可能不理想。我不知道如何做到这一点,否则即使不安全。

然而,这可以通过 Unsize<T> 每晚完成。特征。
#![feature(unsize)]

use std::rc::Rc;
use std::marker::Unsize;

fn to_dyn<DynTrait: ?Sized, Impl>(i: Rc<Impl>) -> Rc<DynTrait>
where
Impl: Unsize<DynTrait> // `Impl` can be "unsized" into `DynTrait`
{
i
}
这是 RFC 982: DST Coercion 的一部分它本身是较大的 RFC 401: Type Conversions 的一部分.

关于rust - 实现伪裸约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65335914/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com