我可以从函数返回一个通用结构吗?

Posted

技术标签:

【中文标题】我可以从函数返回一个通用结构吗?【英文标题】:Can i return a generic struct from function? 【发布时间】:2021-10-18 18:11:09 【问题描述】:

很抱歉,如果下面的答案是直截了当的,但我似乎无法理解。

我需要创建一个 swarm 并将 swarm 返回到主函数,但我不知道如何返回通用结构,例如“P2p”结构。

特征用于抽象方法,所以我不能声明一个来抽象结构的属性。

ps: swarm 是 struct ExpandedSwarm

pps:感谢您的任何意见。


fn create_swarm<T>() -> Result<T, Box<dyn Error>> 
    let local_key = identity::Keypair::generate_ed25519();
    let local_peer_id = PeerId::from(local_key.public());

    println!("Local peer id --> ", local_peer_id);

    let transport = block_on(libp2p::development_transport(local_key))?;
    let behaviour = Ping::new(PingConfig::new().with_keep_alive(true));
    let local_swarm = Swarm::new(transport, behaviour, local_peer_id);
    
    let p = P2p::new(local_swarm);

    Ok(p)



struct P2p <T> 
    swarm: T


impl <T> P2p<T> 
    pub fn new(swarm: T) -> Self 
        return Selfswarm
    



【问题讨论】:

您为什么希望create_swarm 是通用的? T 是一个通用的参数,它是调用者选择的。这里不是这样。 【参考方案1】:

如果您的所有 swarm 类型都实现了相同的 trait,比如 Swarmer,您可以将其装箱,将 P2p 的 swarm 类型设置为 Box&lt;dyn Swarmer&gt; 并返回类型 Result&lt;P2p, Box&lt;dyn Error&gt;&gt;

否则,您需要考虑如何将其抽象化。 create_swarm 函数中的每个变量都必须具有在编译时已知的固定类型。这可以是某种特征对象(装箱或其他),但您永远无法返回任意类型的对象。例如,transport 的每个实例都需要有一个固定的、可识别的类型,这将决定 local_swarm 的类型(假设它是通用的),从而确定 p

如果你真的需要一个任意对象,以后可以向下转换为适当的具体类型,你可以使用Box&lt;dyn Any&gt;(假设你的类型实现了Any)。这就像 C 的void *,在需要在协作函数之间传递不同类型的不透明数据以及在它们之间传递一些不经意的函数时非常有用。但是,您将无法真正调用任何类型的 Swarm 特定方法。

【讨论】:

感谢您的意见!【参考方案2】:

通用参数由调用者选择。这不是这里的情况:因为你的函数自己创建了 swarm,所以函数强加了返回类型。根据您的实际用例,有不同的可能解决方案:

如果调用者不需要能够选择返回类型

只需删除泛型并为您的函数使用常量类型:

fn create_swarm() -> Result<P2p<Swarm>, Box<dyn Error>> 

如果有多个 swarm 类型并且调用者必须能够在编译时选择:

您需要一种通用的方法来创建适当类型的 swarm,这意味着您需要某种为 swarm 定义 new 函数的 SwarmBuilder trait:

trait SwarmBuilder 
    fn new (t: Transport, b: Behaviour, i: PeerId) -> Self;


impl SwarmBuilder for Swarm 
    fn new (t: Transport, b: Behaviour, i: PeerId) -> Self 
        Swarm::new (t, b, i)
    


fn create_swarm<T: SwarmBuilder>() -> Result<P2p<T>, Box<dyn Error>> 
    let local_key = identity::Keypair::generate_ed25519();
    let local_peer_id = PeerId::from(local_key.public());

    println!("Local peer id --> ", local_peer_id);

    let transport = block_on(libp2p::development_transport(local_key))?;
    let behaviour = Ping::new(PingConfig::new().with_keep_alive(true));
    let local_swarm = T::new(transport, behaviour, local_peer_id);
    
    let p = P2p::new(local_swarm);

    Ok(p)

如果有多种 swarm 类型并且调用者必须能够在运行时进行选择:

您需要一个 trait 来定义所有 swarms 共有的行为,并且您需要返回一个装箱的 trait 对象而不是显式类型:

fn create_swarm() -> Result<P2p<Box<dyn SwarmTrait>>, Box<dyn Error>> 

【讨论】:

感谢您的意见!

以上是关于我可以从函数返回一个通用结构吗?的主要内容,如果未能解决你的问题,请参考以下文章

业务层 (BLL) 数据访问层 (DAL) 和 UI 之间的通用结构?

Rust - 我可以让这个柴油 dsl::find() 函数更通用吗?

我可以读取输入数据并创建通用 C++ 数据结构吗?

自定义数据集,例如通用列表的容器

具有通用联合约束的 TypeScript 函数返回值

为啥内核没有收到我的通用网络链接消息?