如何使用解构来可读地处理元组?

时间:2017-12-16 22:15:25

标签: rust

我有这段代码:

fn f(x: &mut (i32, i32)) -> &(i32, i32) {
    x.1 = x.1 + 11;
    x.0 = x.0 * 10;
    x
}

我更愿意:

fn f((x, y) as t: &mut (i32, i32)) -> &(i32, i32) {
    x = x + 11;
    y = y * 10;
    t
}

可以实现这样的可读性吗?

1 个答案:

答案 0 :(得分:4)

  

可以实现这样的可读性吗?

不,不是当前的Rust或计划的未来。 语法类似于您想要存在的内容:

fn f(t @ &mut (ref x, ref y): &mut (i32, i32)) -> &(i32, i32)

但是,不允许:

error[E0007]: cannot bind by-move with sub-bindings
 --> src/main.rs:3:6
  |
3 | fn f(t @ &mut (ref x, ref y): &mut (i32, i32)) -> &(i32, i32) {
  |      ^^^^^^^^^^^^^^^^^^^^^^^ binds an already bound by-move value by moving it

error[E0303]: pattern bindings are not allowed after an `@`
 --> src/main.rs:3:16
  |
3 | fn f(t @ &mut (ref x, ref y): &mut (i32, i32)) -> &(i32, i32) {
  |                ^^^^^ not allowed after `@`

error[E0303]: pattern bindings are not allowed after an `@`
 --> src/main.rs:3:23
  |
3 | fn f(t @ &mut (ref x, ref y): &mut (i32, i32)) -> &(i32, i32) {
  |                       ^^^^^ not allowed after `@`

此类代码的一个棘手方面是您有可变别名 - 您可以通过t.0x更改相同的值。这在Rust中是不允许的。

备受期待的非词汇生存期(NLL)可能会让编译器更好地推理这些案例,但是我没有听到过人们对这个特定方面的看法。

如果您愿意保持灵活性,可以选择以下方式:

fn f(t: &mut (i32, i32)) -> &(i32, i32) {
    {
        let &mut (ref mut x, ref mut y) = t;
        *x = *x + 11;
        *y = *y * 10;
    }
    t
}

在夜间Rust中,这可以简化:

#![feature(match_default_bindings)]

fn f(t: &mut (i32, i32)) -> &(i32, i32) {
    {
        let (x, y) = t;
        *x = *x + 11;
        *y = *y * 10;
    }
    t
}

据我了解,这两种情况都应该由NLL改进。

由于您正在拍摄并返回相同的值引用,因此您可以停止返回它:

fn f(&mut (ref mut x, ref mut y): &mut (i32, i32)) {
    *x = *x + 11;
    *y = *y * 10;
}

同样可以在夜间Rust中改进:

#![feature(match_default_bindings)]

fn f((x, y): &mut (i32, i32)) {
    *x = *x + 11;
    *y = *y * 10;
}