scala 了解如何使用 apply 和 unapply

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18468786/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 05:36:20  来源:igfitidea点击:

Understand how to use apply and unapply

scala

提问by igx

I'm trying to get a better understanding of the correct usage of applyand unapplymethods.

我试图更好地理解applyunapply方法的正确用法。

Considering an object that we want to serialize and deserialize, is this a correct usage (i.e. the Scala way) of using applyand unapply?

考虑到我们要序列化和反序列化对象,这是一个正确的使用(即斯卡拉方式使用)applyunapply

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

回答by amnn

Firstly, applyand unapplyare not necessarily opposites of each other. Indeed, if you define one on a class/object, you don't have to define the other.

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

apply

申请

applyis probably the easier to explain. Essentially, when you treat your object like a function, apply is the method that is called, so, Scala turns:

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

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

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

unapply

不适用

unapplyis a bit more complicated. It is used in Scala's pattern matching mechanism and its most common use I've seen is in Extractor Objects.

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

For example, here's a toy extractor object:

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

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

So now, if you use this is in a pattern match like so:

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

myInt match {
    case Foo(str) => println(str)
}

Let's suppose myInt = 0. Then what happens? In this case Foo.unapply(0)gets called, and as you can see, will return Some("Hello, World"). The contents of the Optionwill get assigned to strso in the end, the above pattern match will print out "Hello, world".

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

But what if myInt = 1? Then Foo.unapply(1)returns Noneso the corresponding expression for that pattern does not get called.

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

In the case of assignments, like val Foo(str) = xthis is syntactic sugar for:

在赋值的情况下,像val Foo(str) = x这样的语法糖用于:

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

回答by Lanny Ripple

So apply and unapply are just defs that have extra syntax support.

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

Apply takes arguments and by convention will return a value related to the object's name. If we take Scala's case classes as "correct" usage then the object Foo's apply will construct a Foo instance without needing to add "new". You are free of course to make apply do whatever you wish (key to value in Map, set contains value in Set, and indexing in Seq come to mind).

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

Unapply, if returning an Option or Boolean can be used in match{} and pattern matching. Like apply it's just a def so can do whatever you dream up but the common usage is to extract value(s) from instances of the object's companion class.

Unapply,如果返回一个 Option 或 Boolean 可以用于 match{} 和模式匹配。就像 apply 它只是一个 def 所以可以做任何你梦寐以求的事情,但常见的用法是从对象的伴生类的实例中提取值。

From the libraries I've worked with serialization/deserialization defs tend to get named explicitly. E.g., write/read, show/read, toX/fromX, etc.

从我使用过序列化/反序列化的库中,def 往往会被明确命名。例如,写入/读取、显示/读取、toX/fromX 等。

If you want to use apply/unapply for this purpose the only thing I'd suggest is changing to

如果您想为此目的使用申请/取消申请,我建议的唯一建议是更改为

def unapply(f: Foo): Option[JValue]

Then you could do something like:

然后你可以做这样的事情:

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

val Foo(jval) = myFoo
// use jval

回答by MJeremy

The applymethod is like a constructor which takes arguments and creates an object, whereas the unapplytakes an object and tries to give back the arguments.

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

A simple example:

一个简单的例子:

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
    }
  }

when you call

你打电话的时候

val file = Foo("test", "txt")

It actually calls Foo.apply("test", "txt")and returns test.txt

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

If you want to deconstruct, call

如果您想解构,请致电

val Foo(name) = file

This essentially invokes val name = Foo.unapply(file).getand returns (test, txt)(normally use pattern matching instead)

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

BTW, the return type of unapplyis Optionby convention.

顺便说一句,返回类型unapplyOption约定俗成的。