【问题标题】:How do I move String values from an array to a tuple without copying?如何在不复制的情况下将字符串值从数组移动到元组?
【发布时间】:2016-11-12 10:43:57
【问题描述】:

我有一个固定大小的数组Strings:[String; 2]。我想把它变成(String, String)。我可以在不复制值的情况下执行此操作吗?

我正在处理的代码如下:

let (basis, names_0, names_1) = if let Some(names) = self.arg_name {
    (ComparisonBasis::Name, names[0], names[1])
} else {
    (ComparisonBasis::File, self.arg_file[0], self.arg_file[1])
};

类型:

self.arg_name: Option<[String; 2]>
self.arg_file: Vec<String>

现在我遇到错误

cannot move out of type `[std::string::String; 2]`, a non-copy fixed-size array [E0508]

cannot move out of indexed content [E0507]

对于if的两条手臂

【问题讨论】:

  • 最后,我想我尝试优化克隆调用有点过分了。每次程序运行时,问题中的代码只被调用一次,它只是两个(可能很小)字符串。

标签: arrays rust tuples


【解决方案1】:

您省略了相当多的上下文,所以我在几个方面进行猜测。我也更接近你提出的问题,而不是你的 sn-ps 所暗示的模糊问题。

struct NeverSpecified {
    arg_names: Option<[String; 2]>,
    arg_file: Vec<String>,
}

impl NeverSpecified {
    fn some_method_i_guess(mut self) -> (String, String) {
        if let Some(mut names) = self.arg_names {
            use std::mem::replace;
            let name_0 = replace(&mut names[0], String::new());
            let name_1 = replace(&mut names[1], String::new());
            (name_0, name_1)
        } else {
            let mut names = self.arg_file.drain(0..2);
            let name_0 = names.next().expect("expected 2 names, got 0");
            let name_1 = names.next().expect("expected 2 names, got 1");
            (name_0, name_1)
        }
    }
}

我使用std::mem::replace 来切换数组的内容,同时使其处于有效状态。这是必要的,因为 Rust 不允许您拥有“部分有效”的数组。此路径中不涉及任何副本或分配。

在另一条路径中,我们必须手动将元素从向量中拉出。同样,您不能仅通过索引将值移出容器(这实际上是整体索引的限制)。相反,我使用Vec::drain 基本上将前两个元素从向量中剔除,然后从生成的迭代器中提取它们。需要明确的是:此路径不涉及任何副本或分配,或者

顺便说一句,那些expect 方法不应该 被触发(因为drain 进行边界检查),但偏执总比抱歉好;如果您想用unwrap() 调用替换它们,那应该没问题..

【讨论】:

  • 这正是我一直在寻找的 :) 抱歉问题含糊不清。
  • @Apanatshka:为了清楚起见,示例中的两个分支都不涉及复制或分配;它是 purely 移动(以及第一个分支中的空值)。只是想澄清一下,因为您对问题的评论可能暗示您认为不复制就无法做到这一点。
  • 我知道您的示例没有进行任何复制(但它确实分配了新的(空的)Strings 对吗?)。我刚刚决定,在这种情况下,调用clone 就可以了,而且编写和阅读的工作量也稍微少了一点:)
  • @Apanatshka 它创建空字符串,但这样做涉及任何实际分配。
【解决方案2】:

从 Rust 1.36 开始,您可以使用 切片模式 一次绑定到数组的所有值:

struct NeverSpecified {
    arg_names: Option<[String; 2]>,
    arg_file: Vec<String>,
}

impl NeverSpecified {
    fn some_method_i_guess(mut self) -> (String, String) {
        if let Some([name_0, name_1]) = self.arg_names.take() {
            (name_0, name_1)
        } else {
            let mut names = self.arg_file.drain(0..2);
            let name_0 = names.next().expect("expected 2 names, got 0");
            let name_1 = names.next().expect("expected 2 names, got 1");
            (name_0, name_1)
        }
    }
}

另见:

【讨论】:

    猜你喜欢
    • 2022-11-08
    • 2018-03-19
    • 2019-11-01
    • 1970-01-01
    • 2016-03-26
    • 2011-02-22
    • 1970-01-01
    • 1970-01-01
    • 2022-01-25
    相关资源
    最近更新 更多