To bardzo stary temat, ale fajny!
Prawdą jest, że przekształcenie dowolnego wyniku trybu Non-wyjątek w Try na Option spowoduje, że ...
scala> Try(null).toOption
res10: Option[Null] = Some(null)
... ponieważ w Try nie chodzi o sprawdzanie wartości null, ale tylko o sposób na funkcjonalną obsługę wyjątków.
Użycie opcji Spróbuj przechwycić wyjątek i przekonwertowanie go na opcję dla wygody spowoduje wyświetlenie Brak tylko w przypadku wystąpienia wyjątku.
scala> Try(1/0).toOption
res11: Option[Int] = None
Chcesz zachować wartości wynikające z Try. To może być nieważne.
Ale prawdą jest również, że standardowa biblioteka czasami jest dość myląca ...
scala> Try(null).toOption
res12: Option[Null] = Some(null)
scala> Option(null)
res13: Option[Null] = None
To zachowanie jest nieco niespójne, ale w pewnym sensie odzwierciedla zamierzone użycie zarówno Try, jak i Option.
Używasz try, aby uzyskać wszystko, co pochodzi z wyrażenia, które może rzucać wyjątki, i nie przejmujesz się samym wyjątkiem.
Wartość, która może się pojawić, może być zerowa. Jeśli toOption dało None, nie możesz odróżnić wyjątku od wartości null , a to nie jest ładne!
Samodzielnie, używasz Option, aby hermetyzować istnienie czegoś lub nie. Więc w tym przypadku Some (null) to None, i to ma sens, ponieważ null w tym przypadku oznacza brak czegoś. Nie ma tu dwuznaczności.
Należy zauważyć, że w żadnym przypadku przezroczystość referencyjna nie jest zepsuta, ponieważ .toOption to nie to samo, co Option ()
Jeśli naprawdę potrzebujesz wymusić ZARÓWNO bezpieczeństwo wyjątków ORAZ bezpieczeństwo zerowe, a Twój kod naprawdę nie musi rozróżniać między wartością zerową a wyjątkiem , wystarczy połączyć oba paradygmaty! Ponieważ cóż, tego właśnie chcesz, prawda?
Możesz to zrobić w jeden sposób ...
scala> Try(Option(null)).getOrElse(None)
res23: Option[Null] = None
scala> Try(Option(3/0)).getOrElse(None)
res24: Option[Int] = None
scala> Try(Option(3)).getOrElse(None)
res25: Option[Int] = Some(3)
... lub inny ...
scala> Try(Option(null)).toOption.flatten
res26: Option[Null] = None
scala> Try(Option(3/0)).toOption.flatten
res27: Option[Int] = None
scala> Try(Option(3)).toOption.flatten
res28: Option[Int] = Some(3)
... lub śmiesznie brzydkie z nich inne ...
scala> Option(Try(null).getOrElse(null))
res29: Option[Null] = None
scala> Option(Try(3/0).getOrElse(null))
res30: Option[Any] = None
scala> Option(Try(3).getOrElse(null))
res31: Option[Any] = Some(3)