当用作隐式方法参数值时,隐式值也可以是一个惰性值吗?

时间:2017-05-29 11:48:59

标签: scala

我有一个使用Slick进行数据库访问的测试套件。此套件中的某些测试访问数据库而某些测试不访问。 我的套房有

implicit val db = DB.getDB

在套件执行开始时有效初始化DataBaseDef。然后,此值将用作某些方法的隐式参数值。 它还有afterAll(),它在套件执行结束时关闭db

override def afterAll():Unit={
    db.close()
    super.afterAll()
  }

现在,如果我改为: implicit lazy val db = DB.getDB 究竟会发生什么?

如果我只运行一个不使用DB的测试,那么连接将不会被初始化,并且afterAll()它仍会尝试关闭连接,在这种情况下我有问题,对吧?我试图运行,但没有发生错误,没有抛出任何异常......

我对implicits的了解不足以帮助我理解它与懒惰的结合。

2 个答案:

答案 0 :(得分:7)

  

那究竟会发生什么?

在第一次访问该值之前,该值不会被初始化。

  

它仍然会尝试关闭连接,我有一个问题   好吧,对吧?

当您访问db.close()时,它会首先初始化该值,这意味着它会在关闭连接之前调用DB.getDb。这意味着,虽然您并不打算这样做,但连接仍会初始化,然后立即关闭,因此您不会看到异常。

答案 1 :(得分:1)

要添加到已接受的答案,我想指出隐式在编译时解决,而val lazy valdef仅在运行时有影响。

如果将标识符定义为隐式标识符,它将告诉编译器您可以访问给定类型的隐式值,因此任何需要这种隐式参数的方法都将使用它;相反,如果您没有声明给定类型的隐式标识符,则对需要该类型值的方法的任何调用都将引发编译器错误。但是,一旦代码被编译,就不再需要implicits了(它们已被相关标识符的显式引用所取代,具体取决于范围)。

现在,在运行时,当一个隐式标识符被调用时,它将使用标准规则进行实例化,因此它可以在定义时进行实例化和memoized,如果它是{{1如果它是val,则在使用时实例化和记忆,或者如果它是lazy val,则在每次使用时实例化。它曾经是一个隐式参数的事实对实例化规则没有影响。