2017-01-06 2 views
5

Ich habe die folgende Definition:Erklärung auf scala für das Verständnis mit Option

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

folgende auswertet auf None:

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

folgende auswertet, um einige (null):

for {x <- f} yield { 
    x 
} 

das folgende ergibt Some (null):

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

Ich frage mich, warum gibt es Unterschiede zwischen ihnen?

Antwort

5

Die Entzuckern geschieht im Parser, so -Xprint:parser zeigt den Unterschied:

$ 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 

Das überrascht mich, weil ich auf diese Weise Filterung dachte, war ein Merkmal Menschen wollten, aber nicht umgesetzt wurde.

Das Muster type ist nur eine instanceof Test, so dass null diesen Test fehlschlägt.

Ohne den Filter:

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) 

in 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) 

so wurde die Filterfunktion in 2.10.x. hinzugefügt

Edit: also eigentlich ist this was bekommt man nicht:

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-difference-in-behavior-between-these-two-pattern-matches-in-a-for- –

1

Nun ... das erste, was ich sagen werde ist, dass "Wenn in Scala-Land, bleiben Sie so weit wie möglich von einem Null-Monster". Die sind Gefährlich.

Nun ... wie dieses Verhalten zu verstehen, das erste, was Sie in Scala-Shell versuchen müssen, ist folgende,

scala> val n = null 
n: Null = null 

So ... In Scala null ist eine Instanz dieser Klasse Null .

Nun ... mal sehen, was passiert, wenn wir diese null mit Option mischen,

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

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

Beachten Sie den Unterschied ... zwischen den beiden ... Also im Grunde Scala Leute dachten, dass es Menschen geben kann, die Willst du eine null in eine Option ... wickeln so erlaubte sie explicitlySome.apply zu verwenden, um diese null in eine Option zu wickeln. Wo sich die Verwendung von Option.apply mehr "intelligent" verhalten und gibt Ihnen eine None, wenn Sie versuchen, eine null zu wickeln.

Nun ... lässt zunächst einen Blick auf, wie map für eine Option implementiert ist,

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

Und jetzt ... sollte klar sein, wie zu „warum Some(null).map((x: String) => x) Sie Some(null) gibt?“.

Was die for Fälle zu verstehen ... das wird ein wenig Verständnis erfordern, wie for für Option mit der Verwendung von Repr ‚s durchgeführt wird. Und das Verhalten wird klar werden.

+1

diese Antwort nicht wirklich die Frage ... –

+0

@ som-snytt ja das ist genau der Punkt. Also ... was auch immer "value" (auch wenn null) war, dass "Some" von 'this.get' zurückgegeben wird und das' f' in diesem Fall nur 'x => x' ist, daher ergibt sich' Einige (null) ' –

+0

Ich kann verstehen, warum Einige (null) .map ((x: String) => x) gibt mir einige (null), was ich nicht verstehe, warum für {x: String <- f} Rendite x gibt mir keine, denn theoretisch sollten sie gleich sein. –