scala apply解析

2020-11-25 14:18:01 浏览数 (1)

一般性应用场景

工厂方法

代码语言:txt复制
package com.qiudaozhang

/**
 * @author 邱道长
 *         2020/11/25
 */
class User(name:String,age:Int) {

  override def toString: String = s"姓名:$name,年龄: $age"
}

object User {
  def apply(name: String, age: Int): User = new User(name, age)
  def apply(name: String): User = new User(name, 18)
}

这样在调用处就可以省略new了。

代码语言:txt复制
val u  =  User("james",23)

函数执行的一般性理论

一切要从数学角度说起,数学家描述函数的时候,并非像程序员那么思考,说调用某个函数,然后传入参数,它们的说法是把函数应用到那些参数上。

根据维基百科的解释:apply是一个将函数应用于参数的函数。听上去有点绕口。

scala设计的apply方法也是桥接OOP和FP编程。

通用的将,任意的一个函数,都是一个将其应用到参数的过程。

案例

代码语言:javascript复制
val f = (x:Int) => x   1

我们都会简单的调用

代码语言:javascript复制
f(3)

一般性的函数调用(程序员角度)一般性的函数调用(程序员角度)

其实它本质也是这样一个过程:

将函数f应用到参数3的函数。

所以我们可以如下写

代码语言:javascript复制
f.apply(3)

apply方式,函数f应用到参数3apply方式,函数f应用到参数3

为何调用伴生对象的时候直接调用的是apply方法?

你是否有这个疑问。

万物皆对象

在scala中,所有的东西都是对象,函数也不例外。

我们来证明这一点,任意的函数都可以是对象,既然是对象,顶部自然是Any,所以可以调用toString方法,hashCode方法等等。

代码语言:javascript复制
f.toString
f.hashCode

函数作为对象调用方法函数作为对象调用方法

如果不是对象,上面必然会报错。

回头看apply

严格来讲所有函数都应该遵循apply的方式,我们前面定义的f函数

代码语言:javascript复制
f.apply(3)

这样写起来很累,所以scala的编译器帮助我们简化了这个过程,只需要我们写

代码语言:javascript复制
f(3)

它就等价于上面的写法。

所以现在我们用同样的理论来看之前的User问题

代码语言:javascript复制
val u  =  User("james",23)

它的调用根据前面的模式推导,自然就是等价于

代码语言:javascript复制
val u  =  User.apply("james",23)

只是它允许我们省略掉apply,这是编译器给与我们的语法糖而已。

至此我相信大家理解了这个apply的原理和逻辑了。 在伴生对象当中定义工厂方法的时候只有命名为apply的时候才能省略,其它方法名都是不可省略名称的。

假设我们修改代码如下,将apply改名

代码语言:javascript复制
package com.qiudaozhang

/**
 * @author 邱道长
 *         2020/11/25
 */
class User(name:String,age:Int) {
  override def toString: String = s"姓名:$name,年龄: $age"
}

object User {
  def myApply(name: String, age: Int): User = new User(name, age)
}

现在你想简化写法必然是失败的

代码语言:javascript复制
val l = User("james",23)

你只能写

代码语言:javascript复制
val l = User.myApply("james",23)

0 人点赞