Элегантный способ заимствовать и вернуть изменчивую ссылку в Rust

Я пытаюсь вернуть изменчивую ссылку после выполнения какой-либо операции над ней. Это лучше всего объяснить фрагментом кода:

#[derive(PartialEq)]
pub enum Value {
    Null,
    Array(Vec<Value>),
}

impl Value {
    pub fn new() -> Value {
        Value::Array(Vec::new())
    }

    pub fn push<'a, T> (&'a mut self, value: T) -> Option<&'a mut Value>
    where T:Into<Value> {
        let temp = match *self {
            Value::Array(ref mut vec) => {
                vec.push(value.into());
                true
            },
            _ => false,
        };
        if temp {
            Some(self)
        } else {
            None
        }
    }
}

#[test]
fn push_test() {
    let mut val = Value::new();
    val.push(Value::Null);
    assert!(val == Value::Array(vec![Value::Null]));
}

Версия игры здесь. Обходной путь с булевыми значениями заключается в том, что, если я вернусь, я заимствую несколько раз Some(self) изнутри match блок. Есть ли элегантный способ реализовать push функция без использования логических значений? Если возможно сохранить подпись функции, то это бонус. Спасибо!

1 ответ

Решение

Обходной путь с булевыми значениями заключается в том, что, если я вернусь, я заимствую несколько раз Some(self) изнутри блока матча

Другим вариантом является замена self временно, так v может взять на себя ответственность за вектор (избегая заимствования). После добавления нового элемента в vмы реконструируем self значение:

// the lifetime 'a can be omitted
pub fn push<T>(&mut self, value: T) -> Option<&mut Value>
    where T: Into<Value>
{
    // replace put Value::Null on self and return the old value
    match ::std::mem::replace(self, Value::Null) {
        Value::Array(mut v) => {
            v.push(value.into());
            *self = Value::Array(v);
            Some(self)
        },
        _ => None,
    }
}
Другие вопросы по тегам