2014-12-17 2 views
7

Исходя из других функциональных языков (и будучи новичком Rust), я немного удивлен мотивацией синтаксиса Rust's if let. RFC упоминает, что без if let, в «идиоматических решения сегодня для тестирования и разворачивания в Option<T>» либоЗачем Rust нужен синтаксис `if let`?

match opt_val { 
    Some(x) => { 
    do_something_with(x); 
    } 
    None => {} 
} 

или

if opt_val.is_some() { 
    let x = opt_val.unwrap(); 
    do_something_with(x); 
} 

В Scala, можно было бы сделать то же самое. Но идиоматическое решение скорее равно map по сравнению с Option (или до foreach, если только для побочного эффекта doing_something_with(x)).

Так что мой вопрос: Почему не идиоматическое решение сделать то же самое в Русте:

opt_val.map(|x| do_something_with(x)); 

ответ

8

.map() специфичен для Option<T> типа, но if letwhile let!) Функции, которые работают со всеми типами ржавчины.

+1

Примечание: Я принимаю этот ответ, потому что он кратко суммирует основные различия _technical_, но см. Ответ @ Vladimir для более полного объяснения. – bluenote10

2

Потому что ваше решение создает замыкание, которое использует ресурсы, в то время как if let desugars именно к вашему первому примеру , чего нет. Я также считаю его более читаемым.

Rust - все о нулевой стоимости абстракций, которые делают программирование приятнее, и if let и while let являются хорошими примерами этих (по крайней мере, ИМО - я понимаю, что это вопрос личных предпочтений). Они не являются абсолютно необходимыми, но они, несомненно, хорошо себя чувствуют (см. Также: Clojure, где они, вероятно, были сняты).

+1

Как я понимаю, они были сняты с [Swift] (https://github.com/rust-lang/rfcs/blob/master/text/0160-if-let.md) – Shepmaster

+0

Итак, другими словами: Картография в порядке, если это не критическая производительность? Учитывая, что синтаксис 'if let' и' map' синтаксически почти идентичны, мне интересно, действительно ли оптимизатор может избежать создания закрытия в первую очередь ... – bluenote10

+3

@ bluenote10 с новым распакованным закрытие, «карта» на самом деле так же быстро, как использование оператора 'match', и, вероятно, компилируется точно таким же кодом, поскольку закрытие статически называется и может быть легко встроено. – reem

13

map() предназначен для преобразующего необязательного значения, в то время как if let в основном необходимо для выполнения побочных эффектов. Хотя Rust не является чистым языком, поэтому любой из его кодовых блоков может содержать побочные эффекты, семантика карты все еще существует. Использование map() для выполнения побочных эффектов, безусловно, возможно, только путает читателей вашего кода. Обратите внимание, что он не должен иметь штрафов за производительность, по крайней мере, в простом коде. Оптимизатор LLVM отлично способен встраивать замыкание непосредственно в вызывающую функцию, поэтому он становится эквивалентным оператору match.

Перед if let единственным способом для выполнения побочных эффектов на условиях Option был либо матчем или if с Option::is_some() чеком. match подхода является самым безопасными один, но очень многословным, особенно когда много вложенных проверки необходимы:

match o1 { 
    Some(v1) => match v1.f { 
     Some(v2) => match some_function(v2) { 
      Some(r) => ... 
      None => {} 
     } 
     None => {} 
    } 
    None => {} 
} 

Обратите внимание известный дрейфа и вправо много синтаксического шум. И только ухудшается, если ветви - это не простые совпадения, а правильные блоки с несколькими утверждениями.

if option.is_some() подход, с другой стороны, немного менее подробный, но все еще читается очень плохо. Также его проверка состояния и unwrap() не статически связаны, поэтому можно ошибиться, если компилятор не заметил это.

if let решает проблему детальности, базируется на той же схеме, соответствующей инфраструктуры, как match (так что это труднее получить неправильно, чем if option.is_some()) и, как побочный эффект, позволяет использовать произвольные типы в образцах, не только Option. Например, некоторые типы могут не предоставлять map()-подобных методов; if let по-прежнему будут работать с ними очень красиво. Таким образом, if let - это явный выигрыш, следовательно, он идиоматичен.

+1

_Использование «карты» для выполнения побочных эффектов только путает читателей вашего кода. Именно поэтому Scala всегда предлагает две версии «карты», одну для преобразования и одну для побочных эффектов. Что мне нравится в подходе Scala, так это то, что он решает ту же проблему без введения дополнительного синтаксиса. Ожидайте, что пользователи Scala будут «сопоставлять» над «Опции» много :) (это повсеместно распространено в Scala). – bluenote10

+1

@ bluenote10, я пишу Scala для жизни, поэтому я прекрасно знаю об этом :) Еще раз обратите внимание, что 'if let' works * не только для' Option' *, а синтаксис, возможно, более легкий, чем с затворы. –