一般性应用场景
工厂方法
代码语言: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方法?
你是否有这个疑问。
万物皆对象
在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)