如果两个变量不是None而不复制它们,我该如何执行操作?

时间:2016-12-29 21:27:53

标签: rust

当且仅当ab不是None时,才会执行操作。我不想创建复杂结构的副本,这就是struct X未实现Clone的原因。

use std::sync::{Arc, Mutex};
use std::cell::RefCell;

#[derive(Debug)]
struct X {
    d: u32,
}

struct Foo {
    a: Option<X>,
    b: Option<u32>,
    c: u32,
}

fn main() {
    let smart_ptr = Arc::new(Mutex::new(RefCell::new(Foo {
        a: Some(X { d: 1 }),
        b: Some(2),
        c: 3,
    })));

    {
        let lock = smart_ptr.lock().unwrap();
        let foo = lock.borrow();
        if let (Some(ref a), Some(b)) = (foo.a, foo.b) {
            println!("a: {:?}, b: {}", a, b);
        }
    }
}

如果我尝试编译此代码,我会得到:

error[E0507]: cannot move out of borrowed content
  --> src/main.rs:25:42
   |
25 |         if let (Some(ref a), Some(b)) = (foo.a, foo.b) {
   |                                          ^^^ cannot move out of borrowed content

如何在没有编译错误的情况下修复if语句以获得我想要的内容?

3 个答案:

答案 0 :(得分:5)

使用较小的例子:

struct Foo {
    a: Option<String>,
    b: Option<String>,
}

fn main() {
    let foo = &Foo {
        a: Some("hi".into()),
        b: Some("world".into()),
    };

    if let (Some(a), Some(b)) = (foo.a, foo.b) {
        println!("a: {}, b: {}", a, b);
    }
}

您可以使用Option::as_ref在引用上执行与the previous answer相同类型的匹配:

if let (Some(a), Some(b)) = (foo.a.as_ref(), foo.b.as_ref()) {
    println!("a: {}, b: {}", a, b);
}

答案 1 :(得分:3)

您需要告诉if let语句仅引用ab引用foo.afoo.b,否则if let会移动一些foo.a从借来的价值中取出的部分。禁止这样做有两个原因:

  1. 引用是不可变的,因此无法更改。
  2. 始终保证引用指向完全有效的对象。如果你可以将a移到foo.a,&#34;偷走&#34;来自贷方的结构,然后foo中的值将不再有效,使Foo::a也无效。
  3. 一种解决方案是通过Foo::b复制值clone()if let (&Some(ref a), &Some(b)) = (&foo.a, &foo.b) { println!("a: {:?}, b: {}", a, b); } ,这是 - 如您所述 - 不需要且性能明智不理想,特别是因为它意味着深层复制

    我没有复制就让它工作了:

    using System;
    using System.Windows.Forms;
    using System.Xml.Linq;
    using System.IO;
    
    namespace SplitXmlFile_41385730
    {
        public partial class Form1 : Form
        {
            public static string incomingXML = @"M:\StackOverflowQuestionsAndAnswers\SplitXmlFile_41385730\SplitXmlFile_41385730\Samples\data.xml";
            public static string outgoingXML = @"M:\StackOverflowQuestionsAndAnswers\SplitXmlFile_41385730\SplitXmlFile_41385730\Samples\data_out.xml";
            public Form1()
            {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                XElement theincomingDoc = new XElement(XDocument.Load(incomingXML).Root);//the incoming XML
    
                //store the header of your files
                XElement header = new XElement(theincomingDoc);
                header.Elements("node6").Remove();//remove these nodes since they need to be parked in their own file
                int fileCounter = 0;//hold on, we'll use this in a moment
    
                //loop through the different nodes you're interested in
                foreach (XElement item in theincomingDoc.Elements("node6"))
                {
                    fileCounter++;//increment the file counter
                    string outfilename = Path.GetDirectoryName(outgoingXML) + "\\" + Path.GetFileNameWithoutExtension(outgoingXML) + fileCounter + Path.GetExtension(outgoingXML);//come up with a file name that suits your needs
                    XDocument newoutfile = new XDocument("", new XElement(header));//create a new document and start it with the header we already stored
                    newoutfile.Element("node1").Add(item);//now add the node you need separated
                    newoutfile.Save(outfilename, SaveOptions.None);//save the file
                }
    
            }
        }
    }
    

答案 2 :(得分:3)

您可以destructure Foo而不是创建元组:

if let Foo { a: Some(ref a), b: Some(b), .. } = *foo {
    println!("a: {:?}, b: {}", a, b);
}