了解如何使用apply和unapply

igx*_*igx 26 scala

我正在努力更好地理解正确的用法applyunapply方法.

考虑到我们想要序列化和反序列化的对象,这是正确的使用(即Scala方式)使用applyunapply

case class Foo
object Foo {
    apply(json: JValue): Foo = json.extract[Foo]
    unapply(f: Foo): JValue = //process to json
}
Run Code Online (Sandbox Code Playgroud)

amn*_*mnn 64

首先,applyunapply不必是相互对立的.实际上,如果在类/对象上定义一个,则不必定义另一个.

应用

apply可能更容易解释.本质上,当你像处理函数一样处理对象时,apply是被调用的方法,因此,Scala转向:

obj(a, b, c)obj.apply(a, b, c).

不应用

unapply有点复杂.它用于Scala的模式匹配机制,我见过的最常见的用途是Extractor Objects.

例如,这是一个玩具提取器对象:

object Foo {
  def unapply(x : Int) : Option[String] = 
    if(x == 0) Some("Hello, World") else None
}
Run Code Online (Sandbox Code Playgroud)

所以现在,如果你使用它就像这样的模式匹配:

myInt match {
    case Foo(str) => println(str)
}
Run Code Online (Sandbox Code Playgroud)

我们假设myInt = 0.然后会发生什么?在这种情况下Foo.unapply(0),调用,如您所见,将返回Some("Hello, World").最终Option将分配给内容str,上面的模式匹配将打印出"Hello,world".

但如果myInt = 1呢?然后Foo.unapply(1)返回,None因此不会调用该模式的相应表达式.

在作业的情况下,像val Foo(str) = x这样是语法糖:

val str : String = Foo.unapply(x) match {
  case Some(s) => s
  case None    => throw new scala.MatchError(x)
}
Run Code Online (Sandbox Code Playgroud)

  • 关键是`str`实际上是一个`String`而不是`Int`,因为这是一种非常特殊的提取器对象:) (3认同)

MJe*_*emy 10

apply方法就像一个构造函数,它接受参数并创建一个对象,而 方法则unapply接受一个对象并尝试返回参数。

一个简单的例子:

object Foo {

    def apply(name: String, suffix: String) = name + "." + suffix

    def unapply(name: String): Option[(String, String)] = {
      //simple argument extractor
      val parts = name.split("\\.")
      if (parts.length == 2) Some(parts(0), parts(1)) else None
    }
  }
Run Code Online (Sandbox Code Playgroud)

你打电话时

val file = Foo("test", "txt")
Run Code Online (Sandbox Code Playgroud)

它实际上调用Foo.apply("test", "txt")并返回test.txt

如果你想解构,请调用

val Foo(name) = file
Run Code Online (Sandbox Code Playgroud)

这本质上是调用val name = Foo.unapply(file).get并返回(test, txt)(通常使用模式匹配)

你也可以直接用2个变量解压元组,即

scala> val Foo(name, suffix) = file
val name: String = test
val suffix: String = txt
Run Code Online (Sandbox Code Playgroud)

顺便说一句,返回类型unapplyOption按照约定的。


小智 5

因此apply和unapply只是具有额外语法支持的def。

Apply接受参数,并且按照约定将返回与对象名称相关的值。如果我们将Scala的案例类作为“正确”用法,则对象Foo的apply将构造一个Foo实例,而无需添加“ new”。您当然可以自由地应用自己想要做的任何事情(想到的就是Map中值的关键,set中Set包含值以及Seq中的索引编制)。

不适用,如果可以在match {}和模式匹配中使用返回的Option或Boolean。就像apply一样,它只是一个def,因此可以做任何您梦dream以求的事情,但是通常的用法是从对象的同伴类实例中提取值。

从我使用过序列化/反序列化的库中,def倾向于显式命名。例如,写入/读取,显示/读取,toX / fromX等。

如果您要为此目的使用Apply / UnApply,我建议的唯一内容就是更改为

def unapply(f: Foo): Option[JValue]
Run Code Online (Sandbox Code Playgroud)

然后,您可以执行以下操作:

val myFoo = Foo("""{name: "Whiskers", age: 7}""".asJson)
// use myFoo

val Foo(jval) = myFoo
// use jval
Run Code Online (Sandbox Code Playgroud)