如何从 Rust 中的 Trait 调用继承的方法

问题描述 投票:0回答:1
pub mod stuff {
    pub trait Clone2: Clone {}
    
    impl<T: Clone> Clone2 for Vec<T> {}
}

fn main() {
    let x: Vec<u32> = Default::default();
    let _ = stuff::Clone2::clone(&x);
}

我想调用

.clone()
Clone
方法,但从特征
Clone2
但由于某种原因它无法编译。有一些注意事项:

  1. 我不想简单地做
    x.clone()
    ,因为我不一定在范围内有
    Clone2
    (也不是事件克隆)。
  2. 我不想使用
    Clone::clone(&x)
    ,因为我需要确保该类型实际实现
    Clone2

这是一个游乐场:https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=2657776369da56fded5b62f5bad16d4d

   Compiling playground v0.0.1 (/playground)
error[E0782]: trait objects must include the `dyn` keyword
 --> src/main.rs:9:13
  |
9 |     let _ = stuff::Clone2::clone(&x);
  |             ^^^^^^^^^^^^^
  |
help: add `dyn` keyword before this trait
  |
9 |     let _ = <dyn stuff::Clone2>::clone(&x);
  |             ++++              +

error[E0038]: the trait `Clone2` cannot be made into an object
 --> src/main.rs:9:34
  |
9 |     let _ = stuff::Clone2::clone(&x);
  |                                  ^^ `Clone2` cannot be made into an object
  |
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
 --> src/main.rs:2:23
  |
2 |     pub trait Clone2: Clone {}
  |               ------  ^^^^^ ...because it requires `Self: Sized`
  |               |
  |               this trait cannot be made into an object...
  = note: required for the cast from `&Vec<u32>` to `&dyn Clone2`

error[E0277]: the size for values of type `dyn Clone2` cannot be known at compilation time
 --> src/main.rs:9:34
  |
9 |     let _ = stuff::Clone2::clone(&x);
  |             -------------------- ^^ doesn't have a size known at compile-time
  |             |
  |             required by a bound introduced by this call
  |
  = help: the trait `Sized` is not implemented for `dyn Clone2`
note: required by a bound in `clone`
 --> /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/core/src/clone.rs:160:5

error[E0038]: the trait `Clone2` cannot be made into an object
 --> src/main.rs:9:13
  |
9 |     let _ = stuff::Clone2::clone(&x);
  |             ^^^^^^^^^^^^^ `Clone2` cannot be made into an object
  |
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
 --> src/main.rs:2:23
  |
2 |     pub trait Clone2: Clone {}
  |               ------  ^^^^^ ...because it requires `Self: Sized`
  |               |
  |               this trait cannot be made into an object...

error[E0038]: the trait `Clone2` cannot be made into an object
 --> src/main.rs:9:13
  |
9 |     let _ = stuff::Clone2::clone(&x);
  |             ^^^^^^^^^^^^^^^^^^^^^^^^ `Clone2` cannot be made into an object
  |
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
 --> src/main.rs:2:23
  |
2 |     pub trait Clone2: Clone {}
  |               ------  ^^^^^ ...because it requires `Self: Sized`
  |               |
  |               this trait cannot be made into an object...

error[E0746]: return type cannot have an unboxed trait object
 --> src/main.rs:9:13
  |
9 |     let _ = stuff::Clone2::clone(&x);
  |             ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
  |
help: box the return type, and wrap all of the returned values in `Box::new`
  |
9 |     let _ = Box<stuff::Clone2::clone>(&x);
  |             ++++                    +

Some errors have detailed explanations: E0038, E0277, E0746, E0782.
For more information about an error, try `rustc --explain E0038`.
error: could not compile `playground` (bin "playground") due to 6 previous errors

现在我发现唯一有效的方法是:

pub mod stuff {
    pub trait Clone2: Clone {}
    
    impl<T: Clone> Clone2 for Vec<T> {}
}

fn main() {
    let x: Vec<u32> = Default::default();
    
    fn clone2_clone<T: stuff::Clone2>(x: &T) -> T {
        x.clone()
    }
    
    let _ = clone2_clone(&x);
}

这还可以,但我真的希望在不定义新函数的情况下做到这一点。

rust traits rust-proc-macros
1个回答
0
投票

最后,我认为我找到的最好的解决方案是复制(没有双关语)他们对

core::mem::copy()
的特征
Copy
所做的事情。

https://doc.rust-lang.org/std/mem/fn.copy.html

按位复制一个值。

这个功能并不神奇;它的字面定义是

pub fn copy<T: Copy>(x: &T) -> T { *x }

当您想要将函数指针传递给组合器而不是定义新的闭包时,它很有用。

示例:

#![feature(mem_copy_fn)]
use core::mem::copy;
let result_from_ffi_function: Result<(), &i32> = Err(&1);
let result_copied: Result<(), i32> = result_from_ffi_function.map_err(copy);

由于我使用的是特征,所以我已将函数作为“提供的方法”放入特征中:

pub mod stuff {
    pub trait Clone2: Clone {
        fn clone2(&self) -> Self {
            Clone::clone(self)
        }
    }
        
    impl<T: Clone> Clone2 for Vec<T> {}
}

fn main() {
    let x: Vec<u32> = Default::default();
    stuff::Clone2::clone2(&x);
}

游乐场:https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=7ed949c36bc6cc98471835e38f8b2f61

© www.soinside.com 2019 - 2024. All rights reserved.