2017-01-06 5 views
5

У меня есть следующее определение:объяснение на Скале для понимания с Вариантом

def f: Option[String] = Some(null) 

следующие принимает значение None:

for {x:String <- f} yield { 
    x 
} 

следующие Оценивает в некоторых (нулевое значение):

for {x <- f} yield { 
    x 
} 

Ниже приведено (null):

f.map((x:String) => x) 

Мне интересно, почему между ними существует разница?

ответ

5

desugaring происходит в парсер, так -Xprint:parser показывает разницу:

$ scala -Xprint:parser 
Welcome to Scala 2.12.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_111). 
Type in expressions for evaluation. Or try :help. 

scala> for (s: String <- (Some(null): Option[String])) yield s 
[[syntax trees at end of     parser]] // <console> 
package $line3 { 
    object $read extends scala.AnyRef { 
    def <init>() = { 
     super.<init>(); 
    () 
    }; 
    object $iw extends scala.AnyRef { 
     def <init>() = { 
     super.<init>(); 
     () 
     }; 
     object $iw extends scala.AnyRef { 
     def <init>() = { 
      super.<init>(); 
     () 
     }; 
     val res0 = (Some(null): Option[String]).withFilter(((check$ifrefutable$1) => check$ifrefutable$1: @scala.unchecked match { 
    case (s @ (_: String)) => true 
    case _ => false 
})).map(((s: String) => s)) 
     } 
    } 
    } 
} 

res0: Option[String] = None 

Это удивляет меня, потому что я думал, что фильтрование таким образом была особенность люди хотели, но не был реализован.

Тип шаблона - это только экземпляр test, поэтому null не подходит для этого теста.

Без фильтра:

scala> for (s <- (Some(null): Option[String])) yield s 
[[syntax trees at end of     parser]] // <console> 
package $line4 { 
    object $read extends scala.AnyRef { 
    def <init>() = { 
     super.<init>(); 
    () 
    }; 
    object $iw extends scala.AnyRef { 
     def <init>() = { 
     super.<init>(); 
     () 
     }; 
     object $iw extends scala.AnyRef { 
     def <init>() = { 
      super.<init>(); 
     () 
     }; 
     val res1 = (Some(null): Option[String]).map(((s) => s)) 
     } 
    } 
    } 
} 

res1: Option[String] = Some(null) 

в 2.9:

$ scala29 
Welcome to Scala version 2.9.3 (OpenJDK 64-Bit Server VM, Java 1.6.0_38). 
Type in expressions to have them evaluated. 
Type :help for more information. 

scala> for (s: String <- (Some(null): Option[String])) yield s 
res0: Option[String] = Some(null) 

поэтому функция фильтрации была добавлена ​​в 2.10.x.

Edit: так на самом деле, this является то, что вы не получите:

scala> for (s: String <- (Some("x"): Option[Any])) yield s 
<console>:12: error: type mismatch; 
found : String => String 
required: Any => ? 
     for (s: String <- (Some("x"): Option[Any])) yield s 
        ^
+0

http://stackoverflow.com/questions/4952124/why-is-there-a-difference-in-behavior-between-these-two-pattern-matches-in-a-for –

1

Ну ... первое, что я скажу, это то, что «Когда в Скала-стране, по возможности, остановитесь от нуль-монстра». Они опасны.

Теперь ... чтобы понять это поведение, то первое, что вам нужно попробовать в Scala-оболочки, следуя

scala> val n = null 
n: Null = null 

Итак ... В Scala null является экземпляром этого класса Null ,

Теперь ... давайте посмотрим, что происходит, когда мы смешиваем это null с Option,

scala> val nullOpt1 = Option(null) 
nullOpt1: Option[Null] = None 

scala> val nullOpt2 = Some(null) 
nullOpt2: Some[Null] = Some(null) 

Обратите внимание на разницу ... между ними ... Так что в основном Scala люди думали, что там могут быть люди, которые хотите обернуть null в Option ... поэтому они разрешили им explicitly использовать Some.apply, чтобы обернуть это null в Option. Где, когда использование Option.apply ведет себя «разумно» и дает вам None, когда вы пытаетесь обернуть null.

Теперь ... давайте сначала рассмотрим, как map реализуется для Option,

final def map[B](f: A => B): Option[B] = 
    if (isEmpty) None else Some(f(this.get)) 

А теперь ... это должно быть ясно, «почему Some(null).map((x: String) => x) дает Some(null)?».

Что касается понять for дел ... что потребует немного понимания того, как for реализуется для Option с использованием Repr-х гг. И поведение станет ясным.

+1

Это не реально ответить на вопрос ... –

+0

@ сома-snytt да это именно точка. Итак ... независимо от того, что «значение» (даже если null) было в том, что 'Some' будет возвращено' this.get', а 'f' в этом случае будет просто' x => x', следовательно, это приведет к ' Some (null) ' –

+0

Я могу понять, почему Some (null) .map ((x: String) => x) дает мне Some (null), что я не понимаю, поэтому для {x: String <- f} выход х дает мне Нет, потому что теоретически они должны быть одинаковыми. –