2014-12-17 28 views
7

Pochodzę z innych języków funkcyjnych (i będąc nowicjuszem Rusta), jestem nieco zaskoczony motywacją składni Rusta if let. RFC wspomina, że ​​bez if let, w „idiomatycznym rozwiązanie dzisiaj dla testowania i rozpakowaniu się Option<T>” jest alboDlaczego Rust potrzebuje składni `if let`?

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

lub

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

W Scala, byłoby możliwe, aby zrobić dokładnie to samo. Ale rozwiązanie idiomatyczne to raczej map niż Option (lub foreach, jeśli jest to tylko efekt uboczny z doing_something_with(x)).

Więc moje pytanie brzmi: Dlaczego nie jest to, że jest to rozwiązanie idiomatyczne zrobić to samo w Rust:

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

Odpowiedz

8

.map() jest specyficzne dla typu Option<T>, ale if let (i while let!) To cechy, które współpracują ze wszystkimi rodzajami korozji.

+1

Uwaga: akceptuję tę odpowiedź, ponieważ krótko podsumowuje ona główną różnicę techniczną, ale patrz odpowiedź @ Vladimira na bardziej wyczerpujące wyjaśnienie. – bluenote10

2

Ponieważ rozwiązanie tworzy zamknięcie, która korzysta z zasobów, podczas gdy if let desugars dokładnie na swoim pierwszym przykładzie , które nie. Uważam też, że jest bardziej czytelny.

Rdza to abstrakcja o zerowym koszcie, która sprawia, że ​​programowanie jest przyjemniejsze, a if let i while let to dobre przykłady (przynajmniej IMO - zdaję sobie sprawę, że to kwestia osobistych preferencji). Nie są one bezwzględnie konieczne, ale na pewno dobrze się z nich korzysta (zobacz także: Clojure, skąd najprawdopodobniej zostały usunięte).

+1

Jak rozumiem, zostały one podniesione z [Swift] (https://github.com/rust-lang/rfcs/blob/master/text/0160-if-let.md) – Shepmaster

+0

Innymi słowy: Mapowanie jest w porządku, jeśli nie jest krytyczne? Biorąc pod uwagę, że składnia 'if let' i' map' są syntaktycznie prawie identyczne, zastanawiam się, czy w ogóle możliwe byłoby, aby optymalizator uniknął tworzenia zamknięcia ... – bluenote10

+3

@ bluenote10 z nowym unboxed 'map' jest tak samo szybkie jak użycie' match' i prawdopodobnie kompiluje się dokładnie do tego samego kodu, ponieważ zamknięcie jest statycznie wywoływane i może być łatwo wbudowane. – reem

13

map() jest przeznaczony do transformującego Wartość opcjonalna, natomiast if let jest najczęściej potrzebne do wykonywania skutki uboczne. Podczas gdy Rust nie jest czystym językiem, więc każdy z jego bloków kodu może zawierać efekty uboczne, semantyka mapy wciąż istnieje. Używanie do działania efektów ubocznych, choć na pewno jest możliwe, tylko myli czytelników twojego kodu. Zauważ, że nie powinien on mieć żadnych kar za wydajność, przynajmniej w prostym kodzie - optymalizator LLVM jest w stanie idealnie zamknąć zamknięcie bezpośrednio w funkcji wywołującej, więc okazuje się być równoważnym z instrukcją match.

Jedynym sposobem na wykonanie efektów ubocznych na było albo dopasowanie, albo if z kontrolą Option::is_some(). match podejście jest najbezpieczniejszym jeden, ale jest bardzo gadatliwy, zwłaszcza gdy wiele zagnieżdżonych kontrole są potrzebne:

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

Uwaga wybitny dryf w prawo i dużo hałasu składniowej. I tylko gorzej, jeśli gałęzie nie są prostymi dopasowaniami, ale właściwymi blokami z wieloma instrukcjami. Z drugiej strony podejście jest nieco mniej szczegółowe, ale nadal bardzo źle czyta. Również jego sprawdzenie kondycji i unwrap() nie są statycznie powiązane, więc możliwe jest pomylenie ich bez zauważenia przez kompilator.

if let rozwiązuje problem gadatliwości, bazuje na tym samym wzorem pasującym infrastruktury jako match (więc trudniej jest dostać złego niż if option.is_some()), a jako korzyść bocznej, pozwala na stosowanie dowolnych typów w wzorów, nie tylko Option. Na przykład niektóre typy mogą nie zapewniać metod podobnych do map(); if let nadal będzie z nimi pracować bardzo ładnie. Tak więc if let jest wyraźną wygraną, dlatego jest idiomatyczna.

+1

_Korzystanie z 'map' do wykonywania efektów ubocznych tylko myli czytelników twojego kodu. Dlatego Scala zawsze oferuje dwie wersje' map', jedną do transformacji i jedną do efektów ubocznych. To co podoba mi się w podejściu Scala polega na tym, że rozwiązuje ten sam problem bez wprowadzania dodatkowej składni. Oczekuj od użytkowników Scala 'mapowania' nad 'Opcjami' dużo :) (jest on wszechobecny w Scali). – bluenote10

+1

@ bluenote10, Piszę Scalę na życie, więc doskonale o tym wiem :) Jeszcze raz zauważ, że 'if let' działa * nie tylko dla' Option' *, a składnia jest prawdopodobnie bardziej lekka niż z zamknięcia. –