2017-09-03 30 views
1

斯卡拉命名提取例如:斯卡拉命名提取器類具有一個參數

class Foo1(n: Int) { 
    def isEmpty: Boolean = 
    false 
    def get: Foo1 = 
    this 
    def _1: Int = n 
} 

object Foo1 { 
    def unapply(arg: Foo1) = arg 
} 

class Foo2(n: Int, nn: Int) { 
    def isEmpty: Boolean = 
    false 
    def get: Foo2 = 
    this 
    def _1: Int = n 
    def _2: Int = nn 
} 

object Foo2 { 
    def unapply(arg: Foo2) = arg 
} 

object Main extends App { 

    new Foo1(1) match { 
    case Foo1(n) if n > 0 ⇒ println(n) 
    } 
    //Error: value > is not a member of Foo1 
    //case Foo1(n) if n > 0 ⇒ println(n) 

    new Foo2(1, 2) match { 
    case Foo2(n, nn) if n > 0 ⇒ println(s"$n -> $nn") 
    } 
    // 1 -> 2 

}

我很好奇,爲什麼斯卡拉提取類的實例作爲一個參數(Foo1),但提取參數(foo2的(n,nn)),如果他們的數量> 1。我錯過了什麼或它的意圖行爲?

回答

0

嗯,我認爲,引入基於命名的提取器的主要原因是使用值類(擴展AnyVal)來提取單個值而不是def unapply(arg: Foo1): Options[Foo1]的可能性。這樣你可以避免額外的實例化Option,從而垃圾收集。通常,這用於提取符合某些標準的值。

例子:

class PositiveNonZeroInteger(private val n: Int) extends AnyVal { 
    def isEmpty: Boolean = n <= 0 
    def get: Int = n 
} 

object PositiveNonZeroInteger { 
    def unapply(arg: Int) = new PositiveNonZeroInteger(arg) 
} 

1 match { 
    case PositiveNonZeroInteger(pos) => "yay" 
    case _       => "nay" 
} // => "yay" 

0 match { 
    case PositiveNonZeroInteger(pos) => "yay" 
    case _       => "nay" 
} // => "nay" 

看來,元組吸氣劑(_1, _2)很可能只能由編譯器解析是否存在至少兩個。

所以,如果你已經重寫你的第一個富來:

class Foo1(private val n: Int) /*extends AnyVal*/ { 
    def isEmpty: Boolean = false 
    def get: Int = n 
} 

object Foo1 { 
    def unapply(arg: Foo1) = arg 
} 

您的代碼將工作,但這不是什麼名字基於提取是。

希望這會有所幫助。

0

Scala語言規範區分以0,1或許多參數的情況下,在萃取圖案:

http://scala-lang.org/files/archive/spec/2.12/08-pattern-matching.html#extractor-patterns

對於1個參數,預計匹配類型的一個選項,即Option[Int]的情況下Foo1和一個元組的Option多個參數。

在您的例子,如果你想通過實施

class Foo1(n: Int) { 
    def get: Int = n 
    ... 
+0

unapply方法,你可以鴨蛋型的Option[Int]預期Foo1返回實例本身我會盡量避免選擇額外的開發 –

+0

然後使用get函數直接返回int,如我的答案中所述。 – Harald