Нет, это небезопасно. Вы пытаетесь ввести изменяемое сглаживание внутри рукава матча. Измененная ссылка a
указывает на то же значение, что и self
. Можно было бы изменить self
(например, *self = Foo::Foo1(99)
), который затем аннулирует a
, поэтому этот код не разрешен.
Вместо этого mutably reborrow self
в выражении match
и вернуть ему первое значение кортежа. Так как это значение не имеет ссылки на self
, вы можете вернуть self
с результатом match
:
enum Foo {
Foo1(u32),
Foo2(u32), // changed so I don't have to figure out what casting you meant
}
impl Foo {
fn bar(&mut self, y: u32) -> (u32, &mut Foo) {
let next = match (&mut *self, y) {
(Foo::Foo1(a), b @ 5) => {
*a = b + 42;
b
}
(Foo::Foo2(a), b @ 5) => {
*a = b + 42;
*a * b
}
_ => y,
};
(next, self)
}
}
Однако возврат self
, как это, скорее здесь бессмысленно. У вызывающего уже есть &mut Foo
, поэтому вам не нужно «возвращать его». Это позволяет упростить:
impl Foo {
fn bar(&mut self, y: u32) -> u32 {
match (self, y) {
(Foo::Foo1(a), b @ 5) => {
*a = b + 42;
b
}
(Foo::Foo2(a), b @ 5) => {
*a = b + 42;
*a * b
}
_ => y,
}
}
}
Я бы сказал, что это безопасная операция, хотя компилятор, возможно, не сможет понять, что
С неэлексические времена жизни , средство проверки займов становится более интеллектуальным. Ваш исходный код с добавленным явным компилятором reborrow:
#![feature(nll)] enum Foo { Foo1(u32), Foo2(u32), // changed so I don't have to figure out what casting you meant } impl Foo { fn bar(&mut self, y: u32) -> (u32, &mut Foo) { match (&mut *self, y) { (Foo::Foo1(a), b @ 5) => { *a = b + 42; (b, self) } (Foo::Foo2(a), b @ 5) => { *a = b + 42; (*a * b, self) } _ => (y, self), } } }
См. Также:
- Почему соответствие по кортежу разыменованных ссылок не работает во время разыменования, -tuples does?
- Каков синтаксис для сопоставления ссылки на перечисление?
- Как использовать совпадение на пару заемных значений без их копирования?
- Есть ли разница между сопоставлением по ссылке на шаблон или разыменованным значением?
Вы можете использовать понимание списка:
In [1]: mylist = [[['1',
...: '1@1`']],
...: [['2', '2@2.com']],
...: [['3', '3@3.com']],
...: [['4', '4@4.com']],
...: [['5', '5@5.com']],
...: [['6', '6@6']],
...: [['7', '7@7']],
...: [['8', '8@8']],
...: [['8.5', '8.5@8.5']],
...: [['9', '9@9']],
...: [['10', '10@10']],
...: [['11', '11@11']],
...: [['12', '12@12']],
...: [['13', '13@13.com']],
...: [['14', '14@14.com']],
...: [['15', '15@15.com']],
...: [['16', '16@16.com']],
...: [['17', '17@17.com']],
...: [['18@18.com', '18']],
...: [['19', '19@19.com']]]
In [2]: [{'id': i, 'email': e} for i, e in (pair[0] if '@' not in pair[0][0] else reversed(pair[0]) for pair in mylist)]
Out[2]:
[{'id': '1', 'email': '1@1`'},
{'id': '2', 'email': '2@2.com'},
{'id': '3', 'email': '3@3.com'},
{'id': '4', 'email': '4@4.com'},
{'id': '5', 'email': '5@5.com'},
{'id': '6', 'email': '6@6'},
{'id': '7', 'email': '7@7'},
{'id': '8', 'email': '8@8'},
{'id': '8.5', 'email': '8.5@8.5'},
{'id': '9', 'email': '9@9'},
{'id': '10', 'email': '10@10'},
{'id': '11', 'email': '11@11'},
{'id': '12', 'email': '12@12'},
{'id': '13', 'email': '13@13.com'},
{'id': '14', 'email': '14@14.com'},
{'id': '15', 'email': '15@15.com'},
{'id': '16', 'email': '16@16.com'},
{'id': '17', 'email': '17@17.com'},
{'id': '18', 'email': '18@18.com'},
{'id': '19', 'email': '19@19.com'}]
Если у вас есть произвольное вложение, вы можете попробовать это:
def flatten(lst):
for sub in lst:
if isinstance(sub, list):
yield from flatten(sub)
else:
yield sub
[{'id': i, 'email': e} for i, e in (pair if '@' not in pair[0] else reversed(pair) for pair in zip(*[flatten(mylist)]*2))]