这是我的“务实”答案:您通常将柯里化用作一种“惯例”,而不是其他任何有意义的东西。当您的最后一个参数恰好是“按名称调用”参数(例如:: => Boolean)时,它会派上用场:
def transaction(conn: Connection)(codeToExecuteInTransaction : => Boolean) = {
conn.startTransaction // start transaction
val booleanResult = codeToExecuteInTransaction //invoke the code block they passed in
//deal with errors and rollback if necessary, or commit
//return connection to connection pool
}
这是说“我有一个名为transaction的函数,它的第一个参数是一个连接,它的第二个参数是一个代码块”。
这允许我们像这样使用这个方法(使用“我可以使用大括号代替括号规则”):
transaction(myConn) {
//code to execute in a transaction
//the code block's last executable statement must be a Boolean as per the second
//parameter of the transaction method
}
如果您不使用该事务方法,那么这样做看起来很不自然:
transaction(myConn, {
//code block
})
implicit 怎么样?是的,它看起来像是一个非常模棱两可的构造,但一段时间后你就会习惯它,隐式函数的好处是它们有范围规则。所以这意味着对于生产,您可以定义一个隐式函数来从 PROD 数据库获取该数据库连接,但是在您的集成测试中,您将定义一个将取代 PROD 版本的隐式函数,它将用于获取连接来自 DEV 数据库,而不是在您的测试中使用。
举个例子,我们给事务方法添加一个隐式参数怎么样?
def transaction(implicit conn: Connection)(codeToExecuteInTransaction : => Boolean) = {
}
现在,假设我的代码库中有一个隐式函数somewhere,它返回一个连接,如下所示:
def implicit getConnectionFromPool() : Connection = { ...}
我可以像这样执行交易方法:
transaction {
//code to execute in transaction
}
Scala 会将其翻译为:
transaction(getConnectionFromPool) {
//code to execute in transaction
}
总而言之,隐式是一种非常好的方法,它不必让开发人员为所需参数提供值,因为该参数在 99% 的时间在您使用该函数的任何地方都是相同的。在这 1% 的时间里你需要一个不同的连接,你可以通过传入一个值来提供你自己的连接,而不是让 Scala 找出哪个隐式函数提供了这个值。