2013-11-24 66 views
0

我想了解在Scala中使用默认的Anorm库在播放框架中的数据库连接。游戏有一个样品例如“计算机数据库”,其中的功能之一尝试检索从DB计算机:在Scala中了解通过名称与currying调用

DB.withConnection { implicit connection => 
    SQL("select * from computer where id = {id}").on('id -> id).as(Computer.simple.singleOpt) 
} 

如果我看withConnection的函数签名是这样的:

def withConnection [A] (block: (Connection) ⇒ A)(implicit app: Application): A 
Execute a block of code, providing a JDBC connection. The connection and all created statements are automatically released. 
**block** Code block to execute. 

我的问题是如何将函数调用的每个值映射到函数定义?例如什么是A(是整个SQL查询,但返回类型的含义是什么?)。在这种情况下,隐含应用程序?它在哪里定义?

回答

3

不可否认这个例子中是混乱的,因为它结合了几种语言特性

  1. 类型参数(泛型)
  2. 钻营(= 2名的参数列表)
  3. 匿名内联函数(功能块)
  4. 隐含参数(从上下文中拾取)

一如既往,艺术变得复杂,让我们一个接一个地梳理出来

(1)A是一个类型参数。这在每次函数调用时都会被合适的类型替换。由于A在参数列表和返回类型中的两个位置被提及,这意味着无论您使用哪种类型,传入功能块的结果类型将与总体返回类型相同。您可以在使用该函数时明确定义A,但通常可以将其忽略,因为编译器可以推断出使用的实际类型。

(2)咖喱很容易理解。这个函数只有两个参数列表。这意味着您可以在几个步骤中应用此功能。首先应用左侧参数列表:

def myBlock(connection:Connection):SQL = 
     SQL("select ......" ..... 

val pf = DB.withConnection(myBlock) 

问题:什么样的对象是pf?什么是ists类型? 回答:它是一个函数,取一个参数,一个应用程序对象

因此PF的类型将是Application => SQL因为在函数的第一,部分应用程序,我们只是在另一个函数通过与返回类型SQL,从而类型参数A被推断为SQL

(3)但在上面的代码中,我们已经以常规方式定义了函数myBlock,并且我们明确给出了名称“myBlock”。这不是必需的。我们可以使用块语法以内联方式定义相同的函数。

(4)现在令人困惑的“魔术”部分,暗示。这是Scala的一个非常特殊的功能,编译器允许您省略一些值或参数(在我们的例子中)。您不能省略任意参数,只能标记为implicit。当你这样做时,编译器不会立即产生错误;而是在当前范围中查找,如果他可以找到一些具有相同名称的其他对象。

实际上,这意味着,在您的示例中,必须以某种方式为Connection类型的值“连接”,并且必须存在Application类型的值“应用程序”。这两个值在当前作用域中必须以某种方式可见 - 也就是说,作为参数,作为封闭作用域中的值或作为伴随对象中的值,或者您可能已使用import语句显式地将它们引入了作用域。这种语言功能的目的只是为了节省你输入那些明显的参数(应用程序和连接9一次又一次地

+0

我明白你说的一个问题,但是:这个SQL查询定义在正在被导入的'package models'中'object Application',那么如何让'Application'对象可见于隐式定义'implicit app:Application' – Richeek

+0

不能给你一个确切的答案,我不得不看看代码。对不对。 只是猜测:也许它是Iherited?或者它可能被导入到一个封闭范围或父类? – Ichthyo

+0

我会检查明天......你提供的例子'def myBlock(connection:Connection):SQL = ... '不起作用,我必须导入'java.sql.Connection'才能找到'Connection'类,但'隐式连接=> ...'不需要导入它。它令人困惑! – Richeek