不可变的字符串和克隆

问题描述 投票:1回答:1

我的心态使我的String保持不变,这是真理的单一来源。当我对Rust采取相同的心态时,我发现我必须做很多克隆工作。由于String不变,因此不需要所有克隆。下面是一个示例和link to the relevant playground

借用似乎不是一个选择,因为我必须处理引用及其生存期。我的下一个想法是使用RcCow结构。但是用String这样的东西包装所有Rc感觉很不自然。根据我对Rust的有限经验,我从未见过任何公开的所有权/内存管理结构,即RcCow。我很好奇Rust开发人员将如何处理这样的问题。

在Rust中公开RcCow之类的所有权/内存管理结构实际上是自然的吗?我应该使用切片吗?

use std::collections::HashSet;

#[derive(Debug)]
enum Check {
    Known(String),
    Duplicate(String),
    Missing(String),
    Unknown(String)
}

fn main() {
    let known_values: HashSet<_> = [
        "a".to_string(),
        "b".to_string(),
        "c".to_string()]
            .iter().cloned().collect();

    let provided_values = vec![
        "a".to_string(),
        "b".to_string(),
        "z".to_string(),
        "b".to_string()
    ];

    let mut found = HashSet::new();

    let mut check_values: Vec<_> = provided_values.iter().cloned()
        .map(|v| {
            if known_values.contains(&v) {
                if found.contains(&v) {
                    Check::Duplicate(v)
                } else {
                    found.insert(v.clone());
                    Check::Known(v)
                }
            } else {
                Check::Unknown(v)
            }
        }).collect();

    let missing = known_values.difference(&found);

    check_values = missing
        .cloned()
        .fold(check_values, |mut cv, m| {
            cv.push(Check::Missing(m));
            cv
        });

    println!("check_values: {:#?}", check_values);
}
memory-management rust ownership ownership-semantics
1个回答
0
投票

从我对问题的评论中的讨论中,示例中所有不可变String的克隆都是正确的。由于Rust通过所有权而不是其他语言的引用来处理内存,因此克隆是必要的。

充其量,不使用Rc,通过使用provided_values上的移动语义,我可以看到克隆的减少。

更新:一些有趣的阅读

Cow在我的示例中不起作用,因为它涉及到引用的借用。我需要使用Rc。在我的示例中,所有内容都必须转换为Rc,但我看到了通过封装将所有内容隐藏起来的可能性。


use std::collections::HashSet;
use std::rc::Rc;

#[derive(Debug)]
enum Check {
    Known(Rc<String>),
    Duplicate(Rc<String>),
    Missing(Rc<String>),
    Unknown(Rc<String>)
}

fn main() {
    let known_values: HashSet<_> = [
        Rc::new("a".to_string()),
        Rc::new("b".to_string()),
        Rc::new("c".to_string())]
            .iter().cloned().collect();

    let provided_values = vec![
        Rc::new("a".to_string()),
        Rc::new("b".to_string()),
        Rc::new("z".to_string()),
        Rc::new("b".to_string())
    ];

    let mut found = HashSet::new();

    let mut check_values: Vec<_> = provided_values.iter().cloned()
        .map(|v| {
            if known_values.contains(&v) {
                if found.contains(&v) {
                    Check::Duplicate(v)
                } else {
                    found.insert(v.clone());
                    Check::Known(v)
                }
            } else {
                Check::Unknown(v)
            }
        }).collect();

    let missing = known_values.difference(&found);

    check_values = missing
        .cloned()
        .fold(check_values, |mut cv, m| {
            cv.push(Check::Missing(m));
            cv
        });

    println!("check_values: {:#?}", check_values);
}

Playground

© www.soinside.com 2019 - 2024. All rights reserved.