Skip to content

zh-cn for Scala Tour:extractor-objects.md #1183

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 4, 2018
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 53 additions & 1 deletion _zh-cn/tour/extractor-objects.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
layout: tour
title: Extractor Objects
title: 提取器对象

discourse: false

Expand All @@ -13,3 +13,55 @@ language: zh-cn
next-page: generic-classes
previous-page: regular-expression-patterns
---

提取器对象是一个包含有 `unapply` 方法的单例对象. `apply` 方法就像一个构造器, 接受参数然后创建一个实例对象, 反之 `unapply` 方法接受一个实例对象然后返回最初创建它所用的参数. 提取器常用在模式匹配和偏函数中.

```tut
import scala.util.Random

object CustomerID {

def apply(name: String) = s"$name--${Random.nextLong}"

def unapply(customerID: String): Option[String] = {
val stringArray: Array[String] = customerID.split("--")
if (stringArray.tail.nonEmpty) Some(stringArray.head) else None
}
}

val customer1ID = CustomerID("Sukyoung") // Sukyoung--23098234908
customer1ID match {
case CustomerID(name) => println(name) // prints Sukyoung
case _ => println("Could not extract a CustomerID")
}
```

这里 `apply` 方法用 `name` 创建一个 `CustomerID` 字符串. 而 `unapply` 方法正好相反, 它返回 `name` . 当我们调用 `CustomerID("Sukyoung")` , 其实是调用了 `CustomerID.apply("Sukyoung")` 的简化语法. 当我们调用 `case CustomerID(name) => println(name)`, 就是在调用提取器方法.

因为在定义一个值的时候可以使用一个模式来引入一个新的变量, 提取器可以用来初始化这个变量, 使用 unapply 方法来生成值.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

变量定义可以使用模式引入变量?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's much better, thanks a lot.


```tut
val customer2ID = CustomerID("Nico")
val CustomerID(name) = customer2ID
println(name) // prints Nico
```

上面的代码等价于 `val name = CustomerID.unapply(customer2ID).get`.

```tut
val CustomerID(name2) = "--asdfasdfasdf"
```

如果没有匹配的值, 会抛出 `scala.MatchError`:

```tut:fail
val CustomerID(name3) = "-asdfasdfasdf"
```

`unapply` 方法的返回值应当符合下面的某一条:

* 如果只是用来测试, 返回一个 `Boolean` 类型的值. 例如 `case even()`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

测试 -> 判断真假?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

语义通顺了很多

* 如果只是用来提取单个 T 类型的值, 返回 `Option[T]`.
* 如果你想要提取多个值, 类型分别为 `T1,...,Tn`, 把它们放在一个可选的元祖中 `Option[(T1,...,Tn)]`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: 元祖 -> 元组

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing it out.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

如果...可以...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot.


有时, 要提取的值的数量不是固定的, 因此我们想根据输入来返回随机数量的值. 这种情况下, 你可以用 `unapplySeq` 方法来定义提取器, 此方法返回 `Option[Seq[T]]`. 常见的例子有, 用 `case List(x, y, z) =>` 来解构一个列表 `List`, 以及用一个正则表达式 `Regex` 来分解一个字符串 `String`, 例如 `case r(name, remainingFields @ _*) =>`.