当前位置:   article > 正文

Rust学习记录 -> 泛型使用:结构体方法,引用和特性_cannot move out of `self.x` which is behind a shar

cannot move out of `self.x` which is behind a shared reference


前言

本文就笔者在学习rust泛型使用时遇到的一个问题进行剖析并给出解决办法


提示:以下是本篇文章正文内容,下面案例可供参考

一、问题简述

首先建立如下包含两个未声明特性的结构体,代码如下:

struct str2<T,E> {
    x:T,
    y:E,
}
  • 1
  • 2
  • 3
  • 4

再对其声明包含的方法:

impl<T,E> str2<T,E> {
    fn get_x(&self) -> &T {
        &self.x
    }

    fn get_y(&self) -> &E {
        &self.y
    }

    fn create<V, W> (self, other: str2<V,W>) -> str2<T,W> {
        str2 {
            x:self.x,
            y:other.y,
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

问题就出现在对create方法的调用上:
创建实例如下所示(接下来文中的实例均引用此处):

let a = str2 {
        x:5,
        y:0.99,
    };
    let b = str2 {
        x:6,
        y:15.6
    };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在简单的观察和实际编译运行后可以发现,create方法虽然可以将两个具有不同泛型的结构体实例拼接后创建一个新的结构体实例。
但是显然,创建之后原来的两个结构体实例就会被drop掉,笔者认为这在实际生产环境中是无法接受的情况,所以开始了对该方法的改进。

二、改进过程

1.使用不可变引用

改进代码如下:

fn create<V, W> (&self, other: &str2<V,W>) -> str2<T,W> {
        str2 {
            x:self.x,
            y:(*other).y,
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在进行如上改进后,本以为可以顺利运行,但是cargo run后发生了报错,具体报错如下所示:

error[E0507]: cannot move out of `self.x` which is behind a shared reference
 --> src/main.rs:9:15
  |
9 |             x:self.x,
  |               ^^^^^^ move occurs because `self.x` has type `T`, which does not implement the `Copy` trait

error[E0507]: cannot move out of `other.y` which is behind a shared reference
  --> src/main.rs:10:15
   |
10 |             y:(*other).y,
   |               ^^^^^^^^^^ move occurs because `other.y` has type `W`, which does not implement the `Copy` trait

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

原以为是我对引用和解引用的应用出现了偏差,但是经过一系列的检查后发现问题不在这里,而是对泛型的声明出了问题

2.声明泛型特性

改进代码如下:

#[derive(Debug)]
struct str2<T:PartialOrd + Copy,E:PartialOrd + Copy> {
    x:T,
    y:E,
}

impl<T:PartialOrd + Copy,E:PartialOrd + Copy> str2<T,E> {
    fn create<V:PartialOrd + Copy,W:PartialOrd + Copy> (&self,other:&str2<V,W>) -> str2<T,W> {
        str2{
            x:self.x,
            y:(*other).y,
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

在刚刚学习泛型时,示例中对涉及的泛型均作了特性的声明,这让我开始怀疑一件事情:是否在使用泛型时,如不提前声明特性,则默认所有泛型实例不具有任何特性?

于是我本着试试的想法,为结构体和方法中的泛型声明添加了特性声明,在编译运行后发现解决了报错问题,成功将两个实例拼接成了第三个新实例并且完整保留了两个旧实例。

fn main() {
    let a = str2 {
        x:5,
        y:0.99,
    };
    let b = str2 {
        x:6,
        y:15.6
    };

    let ab = a.create(&b);

    println!("{:#?}",ab);
    println!("{:?}",a);
    println!("Hello, world!");
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

运行结果如下:

    Finished dev [unoptimized + debuginfo] target(s) in 0.39s
     Running `target/debug/re_stru_T`
str2 {
    x: 5,
    y: 15.6,
}
str2 { x: 5, y: 0.99 }
Hello, world!

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

总结

综上,笔者在解决该问题过程中回顾了引用与解引用的知识,拜读了一些优秀的文章,对泛型在结构体和方法中的使用更熟悉了一些,明白特性在泛型中的特殊性质。如有错误,还请各位大佬指正。

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号