首页 文章

为什么在模式匹配后不会移动此结构?

提问于
浏览
2

基于Preventing move semantics during pattern matching,我的理解是当我在结构上执行 match 时,如果不使用引用来进行匹配,则结构将被移动,因为它不是基本类型 . 为了测试这个,我实现了以下内容:

struct Point {
    x: i32,
    y: i32,
}

let origin = Point { x: 0, y: 0 };

match origin {
    Point { x: x1, y: y1 } => println!("({},{})", x1, y1),
}

// to check if the origin has been moved, and it seems not, why ?? 
match origin {
    Point { x: x1, y: y1 } => println!("({},{})", x1, y1),
}

输出是 (0,0) (0,0) ,这意味着原始结构仍然存在 . 它不应该在第一次 match 之后被移动了吗?

1 回答

  • 5

    重要的不是匹配值的类型,而是每个匹配臂上绑定的每个值的类型 .

    在结构 Point 中,字段 xy 的类型为 i32 . 此类型实现 Copy ,因此Rust将复制此类型的值而不是移动它们 - 这意味着原始值仍被视为有效 . 由于匹配臂上绑定的所有值都实现 Copy ,因此无需使 origin 无效 . 字段访问的工作方式类似: origin.xorigin.x 实现 Copy 时不会使 origin 无效!

    现在,如果字段的类型没有实现 Copy (例如, String ),那么这是一个不同的故事 . Rust被迫将每个 String 从字段移动到匹配臂中的绑定 . 因此, origin 中的字段无效 . 由于我们不能将值与无效字段一起使用,因此整个结构也会失效 .

    让我们稍微调整一下 . 请考虑以下代码:

    struct Point {
        x: i32,
        y: String,
    }
    
    let origin = Point { x: 0, y: "zero".to_string() };
    
    match origin {
        Point { x: x1, y: _ } => println!("({},...)", x1),
    }
    
    match origin {
        Point { x: x1, y: _ } => println!("({},...)", x1),
    }
    
    match origin {
        Point { x: _, y: y1 } => println!("(...,{})", y1),
    }
    
    match origin {
        Point { x: _, y: y1 } => println!("(...,{})", y1),
    }
    

    在这里,我们使用占位符模式( _ )来表示我们对某个字段的值不感兴趣 . 我们也可以使用通配符模式( .. ,如 Point { x: x1, .. } )来忽略结构模式中未命名的所有字段 . 在任何一种情况下,它都具有 not moving the ignored field(s) 的效果 .

    在前两个匹配中,我们仅绑定 x 字段,其类型为 i32 . 由于 i32 实现 Copyorigin 未被无效,即使 originorigin.y 都不可复制( origin.y 只是保持原样) .

    在第三个匹配中,我们只绑定 y 字段,其类型为 String . 由于 String 未实现 Copyorigin.y 被移入 y1 ,因此 origin 无效 . 这会在第四次匹配时导致编译器错误,因为它在失效后尝试使用 origin

    error[E0382]: use of partially moved value: `origin`
      --> <anon>:21:11
       |
    18 |         Point { x: _, y: y1 } => println!("(...,{})", y1),
       |                          -- value moved here
    ...
    21 |     match origin {
       |           ^^^^^^ value used here after move
       |
       = note: move occurs because `origin.y` has type `std::string::String`, which does not implement the `Copy` trait
    
    error[E0382]: use of moved value: `origin.y`
      --> <anon>:22:26
       |
    18 |         Point { x: _, y: y1 } => println!("(...,{})", y1),
       |                          -- value moved here
    ...
    22 |         Point { x: _, y: y1 } => println!("(...,{})", y1),
       |                          ^^ value used here after move
       |
       = note: move occurs because `origin.y` has type `std::string::String`, which does not implement the `Copy` trait
    

相关问题