2017-05-29 115 views
4

我有一個測試套件,它使用Slick進行數據庫訪問。該套件中的一些測試訪問數據庫,有些則不是。 我的套房擁有當作爲隱式方法參數值使用時,隱式值是否也可以是一個惰性值?

implicit val db = DB.getDB

在套件開始執行,有效地初始化DataBaseDef。然後將此值用作某些方法的隱式參數值。 此外,它具有關閉db在套件執行結束的afterAll():如果我改

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

現在: implicit lazy val db = DB.getDB 那麼究竟會怎樣呢?

如果我只運行一個不使用數據庫的測試,那麼連接將不會被初始化,並且在afterAll()它仍然會嘗試關閉連接,在這種情況下我遇到了問題,對不對?我試着跑,但沒有發生錯誤,也沒有發生任何異常......

我對implicits的瞭解還不足以幫助我理解它與懶惰的結合。

回答

7

那麼究竟會發生什麼?

該值在第一次訪問之前不會被初始化。

它仍然會嘗試關閉連接,我在這 的情況下有問題,對不對?

當您訪問db.close(),它會首先初始化值,這意味着它會調用DB.getDb關閉連接之前。這意味着,雖然你不打算,連接仍然會被初始化,然後立即關閉,因此你爲什麼沒有看到異常。

+0

你是對的。發佈這個問題後,我想到了更多,而這一點對我來說變得很清楚 我仍然想澄清'lazy'修飾符對方法調用中隱式參數值發現的影響。你能幫忙嗎? –

+0

或者我可以放心地採用標準規則:如果在規範中沒有關於這方面的信息,懶惰在這方面沒有任何影響? –

+0

@AlexanderArendar如果你有一個被調用的方法需要的'implicit lazy val',它會實現這個值。在你的情況下,它會創建數據庫連接。 –

1

要添加到接受的答案,我想指出隱式在編譯時解析,而vallazy valdef僅在運行時有影響。

如果定義的標識符作爲隱式的,它會告訴編譯器您可以訪問給定類型的一個隱式的值,從而需要這樣的隱式參數將使用它的任何方法;相反,如果您不聲明給定類型的隱式標識符,則對需要該類型值的方法的任何調用都會引發編譯器錯誤。但是,一旦代碼被編譯,就不再需要隱含條目(它們已被對相關標識符的明確引用取代,取決於範圍)。現在

,在運行,當一個隱含的標識被調用時,它將與規則中的標準被實例化,所以它可以是實例化,並在定義memoized如果它是一個val,實例化,並在使用memoized如果它是一個lazy val或在每次使用時實例化,如果它是def。它曾經是一個隱式參數的事實對實例化規則沒有影響。

+0

感謝Cyrille的有用和詳細的澄清。 –

相關問題