0

定型コードをたくさん書きたくなかったので、lazy-init のジェネリック メソッドを書くことにしました。

import java.util._
import concurrent.ConcurrentHashMap

object GenericsTest {
  val cache: ConcurrentHashMap[Long, 
    ConcurrentHashMap[Long, 
      ConcurrentHashMap[Long, 
        ConcurrentHashMap[Long, Long]]]] = new ConcurrentHashMap()

  def main(args: Array[String]) {
    val x = get(cache, 1)(() => new ConcurrentHashMap())
    val y = get(x, 1)(() => new ConcurrentHashMap())
    val z = get(y, 1)(() => new ConcurrentHashMap())
  }

  def get[B, A](map: ConcurrentHashMap[A, B], a: A)(factory: () => B): B = {
    if (map.containsKey(a)) {
      map.get(a)
    } else {
      val b = factory()
      map.put(a, factory())
      b
    }
  }
}

この例は、ハードコーディングされたLongでのみ実行され、一般的なAでは実行されません。何が問題になる可能性がありますか? たぶん、そのようなことを行う別の方法がありますか?

4

1 に答える 1

1

エラーは次の行にあります。

val x = get(cache, 1)(() => new ConcurrentHashMap())

問題は、 1 の型がIntであることです。

このメソッド シグネチャがあります。

get[A, B](map: ConcurrentHashMap[A, B], a: A)(factory: () => B): B

その問題のある呼び出しで渡されるパラメーターの型は次のとおりです (B は長くネストされた型であり、現在は無関係です)。

ConcurrentHashMap[Long, B] and Int

そのため、コンパイラは、 AがLongIntの最も近い共通の祖先 ( AnyVal ) でなければならないと計算、最終的に渡されたパラメータを次の型で使用します。

ConcurrentHashMap[AnyVal, B] and AnyVal

ただし、 ConcurrentHashMap は最初の型パラメーターで不変であるため、キャッシュval をConcurrentHashMap[AnyVal, B]として使用できないため、コンパイラーはこのエラー メッセージを表示します (長いネストされた型パラメーター部分を削除しました。今は問題ありません)。 :

found   : java.util.concurrent.ConcurrentHashMap[Long, ...]
required: java.util.concurrent.ConcurrentHashMap[AnyVal, ...]
Note: Long <: AnyVal, but Java-defined class ConcurrentHashMap is invariant in type K.

これを修正するには、2 番目のパラメーターをLongとして渡す必要があります。

val x = get(cache, 1L)(() => new ConcurrentHashMap())
val y = get(x, 1L)(() => new ConcurrentHashMap())
val z = get(y, 1L)(() => new ConcurrentHashMap())
于 2013-07-23T01:52:28.667 に答える