Scala 了解如何使用apply和unapply

Scala 了解如何使用apply和unapply,scala,Scala,我试图更好地理解apply和unapply方法的正确用法 考虑到我们想要序列化和反序列化的对象,这是使用apply和unapply的正确用法(即Scala方式)吗 case class Foo object Foo { apply(json: JValue): Foo = json.extract[Foo] unapply(f: Foo): JValue = //process to json } 因此,apply和unapply只是具有额外语法支持的def Apply接受参数

我试图更好地理解
apply
unapply
方法的正确用法

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

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

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

Apply接受参数,按照约定将返回与对象名称相关的值。如果我们将Scala的case类视为“正确”用法,那么对象Foo的apply将构造一个Foo实例,而无需添加“new”。当然,您可以自由地让apply做任何您想做的事情(映射中的键到值,set包含set中的值,以及Seq中的索引)

如果返回一个选项,则可以在匹配{}和模式匹配中使用布尔值。就像apply一样,它只是一个def,所以可以做任何你想做的事情,但通常的用法是从对象的伴生类的实例中提取值

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

如果您想为此使用apply/unapply,我唯一建议的就是更改为

def unapply(f: Foo): Option[JValue]
然后你可以做一些类似的事情:

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

val Foo(jval) = myFoo
// use jval

首先,
apply
unapply
不一定是对立的。实际上,如果在类/对象上定义一个,则不必定义另一个

应用
apply
可能更容易解释。本质上,当您将对象视为一个函数时,apply是被调用的方法,因此Scala将:

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

不合时宜
unapply
有点复杂。它在Scala的模式匹配机制中使用,我见过的最常用的用法是

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

object Foo {
  def unapply(x : Int) : Option[String] = 
    if(x == 0) Some("Hello, World") else None
}
现在,如果您在这样的模式匹配中使用它:

myInt match {
    case Foo(str) => println(str)
}
让我们假设
myInt=0
。那会发生什么?在本例中,
Foo.unapply(0)
被调用,如您所见,将返回
Some(“Hello,World”)
选项
的内容将分配给
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)
}

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
    }
  }
当你打电话的时候

val file = Foo("test", "txt")
它实际上调用
Foo.apply(“test”,“txt”)
并返回
test.txt

如果您想解构,请致电

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


顺便说一句,
unapply
的返回类型按惯例是
Option

有点奇怪,你称int
str
,但除此之外,解释得很好;)关键是
str
实际上是一个
String
而不是
Int
,因为这是一种非常特殊的提取器对象:)最好说明您不必返回
选项
某些
,特别是:Unapply可以返回任何具有
get
isEmpty
方法(例如
选项
)或
布尔值的对象。apply“接受参数并创建对象”-不一定。这只是一种方法。它不需要获取、创建或返回任何内容。这通常是一种工厂方法,但这只是一种惯例。取消应用“返回类型…需要是
选项
”-。使用
选项
是一种方便,而不是一种要求。是否应该
val Foo(name)=file
be
val Foo(name,ext)=file
?我们期待着两个论点的反驳。