简体   繁体   English

在将值移入元组类型枚举变体后,如何轻松获取对值的引用?

[英]How can I easily get a reference to a value after it has been moved into a tuple-type enum variant?

I want to move a value into a tuple-type enum variant and obtain a reference to the value after it has been moved.我想将一个值移动到元组类型的枚举变体中,并在移动后获取对该值的引用。 I see how this is possible with an if let statement, but this seems like this should be unnecessary when the particular variant is known statically.我看到了如何使用if let语句实现这一点,但是当静态知道特定变体时,这似乎是不必要的。

Is there any way to get the reference to the moved value without requiring an if let or match ?有没有办法在不需要if letmatch的情况下获取对移动值的引用?

This code block is a simple illustration of my question (see below for a more challenging case):此代码块是我的问题的简单说明(请参阅下面的更具挑战性的案例):

enum Transport {
    Car(u32),      // horsepower
    Horse(String), // name
}

fn do_something(x: &String) {
    println!(x);
}

fn main() {
    // Can I avoid needing this if, which is clearly redundant?
    if let Transport::Horse(ref name) = Transport::Horse("daisy".into()) {
        do_something(name);
    }
    else {
        // Can never happen
    }

    // I tried the following, it gives:
    //     "error[E0005]: refutable pattern in local binding: `Car(_)` not covered"
    let Transport::Horse(ref name) = Transport::Horse("daisy".into());
}

It is easy to find ways to side-step the issue in the above code, since there are no real interface requirements.在上面的代码中很容易找到回避问题的方法,因为没有真正的接口要求。 Consider instead the following example, where I am building a simple API for building trees (where each node can have n children).请考虑以下示例,我正在构建一个简单的 API 来构建树(其中每个节点可以有n个子节点)。 Nodes have an add_child_node method returning a reference to the node that was added, to allow chaining of calls to quickly build deep trees.节点有一个add_child_node方法返回对已添加节点的引用,以允许链接调用以快速构建深层树。 (It is debatable whether this is a good API, but that is irrelevant to the question). (这是否是一个好的 API 值得商榷,但这与问题无关)。 add_child_node must return a mutable reference to the contents of an enum variant. add_child_node必须返回对枚举变量内容的可变引用。 Is the if let required in this example (without changing the API)?此示例中是否需要if let (不更改 API)?

struct Node {
    children: Vec<Child>,
    // ...
}

enum Child {
    Node(Node),
    Leaf
}

impl Node {
    fn add_child_node(&mut self, node: Node) -> &mut Node {
        self.children.push(Child::Node(node));

        // It seems like this if should be unnecessary
        if let Some(&mut Child::Node(ref mut x)) = self.children.last() {
            return x;
        }

        // Required to compile, since we must return something
        unreachable!();
    }

    fn add_child_leaf(&mut self) {
        // ...
    }
}

No. You can use unreachable!() for the else case, and it's usually clear even without message/comment what's going on.不。您可以使用unreachable!()来处理else情况,即使没有消息/评论也通常很清楚发生了什么。 The compiler is also very likely to optimize the check away.编译器也很有可能优化检查。

If the variants have the same type you can implement AsRef and use the Transport as a &str :如果变体具有相同的类型,您可以实现AsRef并将 Transport 用作&str

enum Transport {
    Car(String),
    Horse(String),
}

fn do_something<S: AsRef<str>>(x: &S) {
    println!("{}", x.as_ref());
}

impl AsRef<str> for Transport {
    fn as_ref(&self) -> &str {
        match self {
            Transport::Car(s) => s,
            Transport::Horse(s) => s,
        }
    }
}

fn main() {
    let transport = Transport::Horse("daisy".into());
    do_something(&transport)
}

Playground 操场

Otherwise you need to use a let if binding as you are doing.否则,您需要像现在一样使用let if绑定。 No need to use an else clause if you don't want to :如果您不想,则无需使用 else 子句

if let Transport::Horse(ref name) = Transport::Horse("daisy".into()) {
    do_something(name);
}

define From<Transport> for String : From<Transport> for String

…

impl From<Transport> for String {
    fn from(t: Transport) -> String {
        match t {
            Transport::Car(value)  => value.to_string(),
            Transport::Horse(name) => name,
        }
    }
}

fn do_something(x: Transport) {
    println!("{}", String::from(x));
}


fn main() {
    let horse = Transport::Horse("daisy".to_string());
    let car = Transport::Car(150);
    do_something(horse);
    do_something(car);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 我可以将元组结构枚举变量转换为常规元组,而不是解构和重新创建元组吗? - Can I cast a tuple struct enum variant into a regular tuple instead of destructuring and recreating the tuple? 如何使用模式匹配来获取对 Rc 内 f64 值的引用<enum::variant(f64)>没有克隆?</enum::variant(f64)> - How can I use a pattern match to get a reference to an f64 value inside an Rc<Enum::Variant(f64)> without cloning? 如何根据与变体中的类型匹配的泛型类型选择枚举变体? - How can I select an enum variant based on a generic type that matches a type inside the variant? 如何动态确定枚举的变体 - How can I dynamically determine the variant of an enum 如何对枚举进行变异,然后返回对枚举变体的引用? - How do I mutate an enum and then return a reference to an enum variant? 如何将类型声明为“枚举变体之一或无”? - How do I declare a type as "one of an enum variant or a None"? Rust 将值传递给枚举变量时出现“使用移动值”错误 - Rust 'use of moved value' error when passing value into Enum variant 将键插入 HashMap 后,如何保留对键的引用? - How can I keep a reference to a key after it has been inserted into a HashMap? 当给定的枚举不是某种变体时,如何返回None? - How can I return None when a given enum is not a certain variant? 路径移动后,如何给定路径的文件重命名? - How can I rename a file given a Path once the path has been moved?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM