Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Generics 通用可克隆/可移动参数作为函数参数_Generics_Rust - Fatal编程技术网

Generics 通用可克隆/可移动参数作为函数参数

Generics 通用可克隆/可移动参数作为函数参数,generics,rust,Generics,Rust,对于实现Clone的任意结构,我希望有一个通用函数,该函数可以采用以下两种方式之一: 一个&MyStruct,在这种情况下,函数可以有条件地克隆它 aMyStruct在这种情况下,克隆是不必要的,因为它可以移动 我自己实现了这一点: use std::clone::Clone; #[derive(Debug)] struct MyStruct { value: u64, } impl Clone for MyStruct { fn clone(&self) -&g

对于实现
Clone
的任意结构,我希望有一个通用函数,该函数可以采用以下两种方式之一:

  • 一个
    &MyStruct
    ,在这种情况下,函数可以有条件地克隆它
  • a
    MyStruct
    在这种情况下,克隆是不必要的,因为它可以移动
我自己实现了这一点:

use std::clone::Clone;

#[derive(Debug)]
struct MyStruct {
    value: u64,
}

impl Clone for MyStruct {
    fn clone(&self) -> Self {
        println!("cloning {:?}", self);
        MyStruct { value: self.value }
    }
}

trait TraitInQuestion<T> {
    fn clone_or_no_op(self) -> T;
}

impl TraitInQuestion<MyStruct> for MyStruct {
    fn clone_or_no_op(self) -> MyStruct {
        self
    }
}

impl<'a> TraitInQuestion<MyStruct> for &'a MyStruct {
    fn clone_or_no_op(self) -> MyStruct {
        self.clone()
    }
}

fn test<T: TraitInQuestion<MyStruct>>(t: T) {
    let owned = t.clone_or_no_op();
}

fn main() {
    let a = MyStruct { value: 8675309 };

    println!("borrowing to be cloned");
    test(&a);

    println!("moving");
    test(a);
}
通过实现
克隆
,是否已经派生出此功能?如果没有,听起来像是我想要的,但我无法让它工作:

use std::clone::Clone;
use std::borrow::Borrow;

#[derive(Debug)]
struct MyStruct {
    value: u64,
}

impl Clone for MyStruct {
    fn clone(&self) -> Self {
        println!("cloning {:?}", self);
        MyStruct { value: self.value }
    }
}

fn test<T: ToOwned<Owned = MyStruct>>(a: T) {
    let owned = a.to_owned();
}

fn main() {
    let a = MyStruct { value: 8675309 };

    println!("borrowing to be cloned");
    test(&a);

    println!("moving");
    test(a);
}
以及由此产生的错误:

错误[E0308]:类型不匹配
-->src/main.rs:27:10
|
27 |测试和分析;
|^^应为结构'MyStruct',已找到&MyStruct
|
=注意:应为'MyStruct'类型`
找到类型“%MyStruct”`
如果我尝试为
&MyStruct

impl<'a> ToOwned for &'a MyStruct {
    type Owned = MyStruct;

    fn to_owned(&self) -> Self::Owned {
        self.clone()
    }
}
impl Self::Owned{
self.clone()
}
}
我得到以下错误:

error[E0119]:类型`&MyStruct`:
-->src/main.rs:16:1
|
16 |/impl Self::Owned{
20 | | self.clone()
21 | |     }
22 | | }
| |_^
|
=注意:板条箱'alloc'中的实现冲突`

正如@Shepmaster指出的那样;但是您需要手动创建
Cow::followed(&a)
Cow::Owned(a)
实例,而wrapped(
Owned
)类型必须始终实现
Clone
(对于
T:ToOwned

(对于自定义的
ToOwned
实现,
ToOwned::Owned
Clone
可能不是严格必需的;但是
.borrow().to_Owned()
的行为类似于
.Clone()
,因此没有理由隐藏它。)

您自己的特性是另一种选择的良好开端,尽管您应该使用通用实现。这样,只要不传递引用,就不需要类型来实现
Clone

编译器看到类型
&
的“
CloneOrNoOp
实现冲突(有些疯子可能会为Foo实现
ToOwned{type Owned=&'static Foo;…}
;traits无法根据生存期差异区分实现)

但与
ToOwned
类似,您可以实现特定的定制,如:

impl<'a> CloneOrNoOp<String> for &'a str {
    fn clone_or_no_op(self) -> String {
        self.to_owned()
    }
}

你已经熟悉了
Cow
?高度相关:哦,我不知道
Cow
。。这正是我想要的,一定错过了。尽管如此,在某些情况下,似乎没有必要将输入包装到枚举中(例如,
Cow
是动态调度,正如我的
TraitInQuestion
是静态调度,如果这种类比有意义的话)
trait CloneOrNoOp<T> {
    fn clone_or_no_op(self) -> T;
}

impl<T> CloneOrNoOp<T> for T {
    fn clone_or_no_op(self) -> T {
        self
    }
}

impl<'a, T: Clone> CloneOrNoOp<T> for &'a T {
    fn clone_or_no_op(self) -> T {
        self.clone()
    }
}

struct MyStructNoClone;

#[derive(Debug)]
struct MyStruct {
    value: u64,
}

impl Clone for MyStruct {
    fn clone(&self) -> Self {
        println!("cloning {:?}", self);
        MyStruct { value: self.value }
    }
}

fn test<T: CloneOrNoOp<MyStruct>>(t: T) {
    let _owned = t.clone_or_no_op();
}

// if `I` implement `Clone` this takes either `&I` or `I`; if `I` doesn't
// implement `Clone` it still will accept `I` (but not `&I`).
fn test2<I, T: CloneOrNoOp<I>>(t: T) {
    let _owned: I = t.clone_or_no_op();
}

fn main() {
    let a = MyStruct { value: 8675309 };

    println!("borrowing to be cloned");
    test(&a);
    // cannot infer `I`, could be `&MyStruct` or `MyStruct`:
    // test2(&a);
    test2::<MyStruct,_>(&a);
    test2::<&MyStruct,_>(&a);

    println!("moving");
    test(a);

    let a = MyStructNoClone;
    test2(&a);
    // the previous line is inferred as ("cloning" the reference):
    test2::<&MyStructNoClone,_>(&a);
    // not going to work (because it can't clone):
    // test2::<MyStructNoClone,_>(&a);

    test2(a);
}
impl<'a, B> CloneOrNoOp<B::Owned> for &'a B
where
    B: ToOwned,
{
    fn clone_or_no_op(self) -> B::Owned {
        self.to_owned()
    }
}
impl<'a> CloneOrNoOp<String> for &'a str {
    fn clone_or_no_op(self) -> String {
        self.to_owned()
    }
}
test2::<String,_>("abc");
test2::<String,_>(&String::from("abc"));
test2::<String,_>(String::from("abc"));