我正在尝试使用play框架中的默认Anorm库来理解Scala中的数据库连接。 Play有一个示例示例“计算机数据库”,其中一个函数尝试从数据库中检索计算机:
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查询,但返回类型的含义是什么?)。在这种情况下,隐式应用是什么?在哪里定义?
答案 0 :(得分:3)
不可否认,这个例子令人困惑,因为它结合了多种语言功能
与往常一样,当事情开始变得复杂时,让我们一个接一个地排序
(1)A是类型参数。在每次调用函数时,它都会被合适的类型替换。由于在参数列表和返回类型中的两个位置提到A
,这意味着无论使用何种类型,传入函数块的结果类型都将与整体返回类型相同。您可以在使用该函数时明确定义A
,但通常您可以将其保留,因为编译器可以推断出实际使用的类型。
(2)currying很容易理解。这个函数只有两个参数列表。这意味着您可以分几步应用此功能。首先应用左参数列表:
def myBlock(connection:Connection):SQL =
SQL("select ......" .....
val pf = DB.withConnection(myBlock)
问题:pf
是什么类型的对象? ists类型是什么?
答:它是一个函数,带一个参数,一个Application对象
因此pf的类型将是Application => SQL
,因为在函数的第一个部分应用中,我们只传递了另一个返回类型为SQL的函数,因此类型参数A
被推断为{ {1}}
(3)但是在上面的代码中,我们以传统的方式定义了函数SQL
,我们明确地给它命名为“myBlock”。这不是必需的。我们可以使用块语法直接定义相同的函数。
(4)现在是令人困惑的“神奇”部分,暗示。这是Scala的一个非常特殊的功能,编译器允许您省略某些值或参数(在我们的例子中)。您不能省略任意参数,只能省略标记为myBlock
的参数。执行此操作时,编译器不会立即生成错误;而是在当前范围内查找,如果他能找到一些合适的其他具有相同名称的对象。
实际上,这意味着,在您的示例中,必须以某种方式成为类型implicit
的值“连接”,并且必须存在类型为Connection
的值“应用程序”。这两个值必须在当前作用域中以某种方式显示 - 即,作为参数,作为封闭作用域中的值,或作为伴随对象中的值,或者您可能已使用import语句将它们显式地带入作用域。这种语言功能的目的只是为了节省您输入那些明显的参数(应用程序和连接9一次又一次