-
Notifications
You must be signed in to change notification settings - Fork 1k
Tour:higher-order-functions for zh-cn #1155
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
Changes from 4 commits
e363993
2cbe9ba
578bcf6
22e34da
24787bb
eb8e6be
e22f219
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
--- | ||
layout: tour | ||
title: Higher-order Functions | ||
title: 高阶函数 | ||
|
||
discourse: false | ||
|
||
|
@@ -13,3 +13,98 @@ language: zh-cn | |
next-page: nested-functions | ||
previous-page: mixin-class-composition | ||
--- | ||
|
||
高阶函数是指使用其他函数作为参数、或者返回一个函数作为结果的函数。在Scala中函数是“一等公民”,所以允许定义高阶函数。 | ||
这里的术语可能有点让人困惑:使用函数作为参数,或者返回值为函数的“函数”和“方法”,我们均称之为“高阶函数”。 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 原文是一个段落,不知道这里另起一行有没有影响,会不会在两句话之间加一个空格。
在《Pragmatic Scala》,将一个函数作为一个值来使用的时候,都是用 function value 的,这里建议翻译成 函数值 。这样就不那么绕口。 后面我提一个PR,去建议改一下英文原文。 |
||
|
||
最常见的一个例子是Scala中容器类(Collections)的高阶函数`map` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One of the most common examples is the higher-order function map which is available for collections in Scala.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. container是容器,collection是集合 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
``` | ||
val salaries = Seq(20000, 70000, 40000) | ||
val doubleSalary = (x: Int) => x * 2 | ||
val newSalaries = salaries.map(doubleSalary) // List(40000, 140000, 80000) | ||
``` | ||
函数`doubleSalary`有一个整型参数`x`,返回`x * 2`。一般来说,在`=>`左边的元组是函数的参数列表,而右边表达式的值则为函数的返回值。 | ||
在第3行,函数`doubleSalary`被应用在列表`salaries`中的每一个元素。 | ||
|
||
为了简化压缩代码,我们可以使用匿名函数,直接作为参数传递给`map`: | ||
``` | ||
val salaries = Seq(20000, 70000, 40000) | ||
val newSalaries = salaries.map(x => x * 2) // List(40000, 140000, 80000) | ||
``` | ||
注意在上述示例中`x`没有被显式声明为Int类型,这是因为编译器能够根据map函数期望的类型推断出`x`的类型。对于上述代码,一种更惯用的写法为: | ||
```tut | ||
val salaries = Seq(20000, 70000, 40000) | ||
val newSalaries = salaries.map(_ * 2) | ||
``` | ||
既然Scala编译器已经知道了参数的类型(一个单独的Int),你可以只给出函数的右半部分,不过需要使用`_`代替参数名(在上一个例子中是`x`) | ||
|
||
## 强制转换方法为函数 | ||
你同样可以传入一个对象方法作为高阶函数的参数,这是因为Scala编译器会将方法强制转换为一个函数。 | ||
``` | ||
case class WeeklyWeatherForecast(temperatures: Seq[Double]) { | ||
|
||
private def convertCtoF(temp: Double) = temp * 1.8 + 32 | ||
|
||
def forecastInFahrenheit: Seq[Double] = temperatures.map(convertCtoF) // <-- passing the method convertCtoF | ||
} | ||
``` | ||
在这个例子中,方法`convertCtoF`被传入`forecastInFahrenheit`。 | ||
这是可以的,因为编译器强制将方法`convertCtoF`转成了函数`x => convertCtoF(x)` | ||
(注: `x`是编译器生成的变量名,保证在其作用域是唯一的)。 | ||
|
||
## 接收函数作为参数的函数 | ||
使用高阶函数的一个原因是减少冗余的代码。比方说需要写几个方法以通过不同方式来提升员工工资,若不使用高阶函数,代码可能像这样: | ||
```tut | ||
object SalaryRaiser { | ||
|
||
def smallPromotion(salaries: List[Double]): List[Double] = | ||
salaries.map(salary => salary * 1.1) | ||
|
||
def greatPromotion(salaries: List[Double]): List[Double] = | ||
salaries.map(salary => salary * math.log(salary)) | ||
|
||
def hugePromotion(salaries: List[Double]): List[Double] = | ||
salaries.map(salary => salary * salary) | ||
} | ||
``` | ||
|
||
注意这三个方法的差异仅仅是提升的比例不同,为了简化代码,其实可以把重复的代码提到一个高阶函数中: | ||
|
||
```tut | ||
object SalaryRaiser { | ||
|
||
private def promotion(salaries: List[Double], promotionFunction: Double => Double): List[Double] = | ||
salaries.map(promotionFunction) | ||
|
||
def smallPromotion(salaries: List[Double]): List[Double] = | ||
promotion(salaries, salary => salary * 1.1) | ||
|
||
def bigPromotion(salaries: List[Double]): List[Double] = | ||
promotion(salaries, salary => salary * math.log(salary)) | ||
|
||
def hugePromotion(salaries: List[Double]): List[Double] = | ||
promotion(salaries, salary => salary * salary) | ||
} | ||
``` | ||
|
||
新的方法`promotion`有两个参数,薪资列表和一个`Double => Double`的函数(输入Double参数返回Double的函数),返回薪资提升的结果。 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 一个类型为 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 参数类型和结果类型都是 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
|
||
## 返回函数的函数 | ||
|
||
有一些情况你希望生成一个函数, 比如: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
```tut | ||
def urlBuilder(ssl: Boolean, domainName: String): (String, String) => String = { | ||
val schema = if (ssl) "https://" else "http://" | ||
(endpoint: String, query: String) => s"$schema$domainName/$endpoint?$query" | ||
} | ||
|
||
val domainName = "www.example.com" | ||
def getURL = urlBuilder(ssl=true, domainName) | ||
val endpoint = "users" | ||
val query = "id=1" | ||
val url = getURL(endpoint, query) // "https://www.example.com/users?id=1": String | ||
``` | ||
|
||
注意urlBuilder的返回类型是`(String, String) => String`,这意味着返回的匿名函数有两个String参数,返回一个String。 | ||
在这个例子中,返回的匿名函数是`(endpoint: String, query: String) => s"https://www.example.com/$endpoint?$query"`。 |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这里强调的是 函数 是 一种 值,而且是first-class的,也就是和其他的值,比如1、2.0, 是同等地位的。
如果翻译成 函数是一等值,感觉比较奇怪,所以我这边做了一下处理。
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
因为在Scala中函数是一种值,且是”一等公民“
首先这样翻译多多少少让人感觉:只有函数是“一等公民”
其次我觉得不应该把这句和之前的高阶函数定义分开翻译,要有呼应,不然显得没有过渡
综上,个人还是建议: