이것은 간단하지 않습니다.
값의 유형은 키에 따라 다릅니다. 그래서 열쇠는 그 값이 어떤 타입인지에 관한 정보를 가지고 있어야합니다. 이것은 일반적인 패턴입니다. 예를 들어 SBT (예 : SettingsKey[T] 참조) 및 쉐이프 레스 레코드 (Example 참조)에서 사용됩니다. 그러나 SBT에서 키는 자체의 거대하고 복잡한 클래스 계층이며 셰이프가없는 HList는 매우 복잡하며 원하는 것 이상을 수행합니다.
이렇게 구현할 수있는 방법은 다음과 같습니다.키는 유형을 알고 있으며, 레코드를 작성하거나 레코드에서 값을 가져 오는 유일한 방법이 키입니다. Map [Key, Any]를 내부적으로 저장소로 사용하지만 캐스트가 숨겨져 성공할 수 있습니다. 키로 레코드를 생성하는 연산자와 레코드를 병합하는 연산자가 있습니다. 대괄호를 사용하지 않고 레코드를 연결할 수 있도록 연산자를 선택했습니다.
sealed trait Record {
def apply[T](key:Key[T]) : T
def get[T](key:Key[T]) : Option[T]
def ++ (that:Record) : Record
}
private class RecordImpl(private val inner:Map[Key[_], Any]) extends Record {
def apply[T](key:Key[T]) : T = inner.apply(key).asInstanceOf[T]
def get[T](key:Key[T]) : Option[T] = inner.get(key).asInstanceOf[Option[T]]
def ++ (that:Record) = that match {
case that:RecordImpl => new RecordImpl(this.inner ++ that.inner)
}
}
final class Key[T] {
def ~>(value:T) : Record = new RecordImpl(Map(this -> value))
}
object Key {
def apply[T] = new Key[T]
}
사용 방법은 다음과 같습니다. 우선 몇 가지 키를 정의 :
val a = Key[Int]
val b = Key[String]
val c = Key[Float]
을 다음 기록
val record = a ~> 1 ++ b ~> "abc" ++ c ~> 1.0f
키를 사용하여 기록에 액세스 할 때, 다시 올바른 유형의 값을 얻을 것이다
scala> record(a)
res0: Int = 1
scala> record(b)
res1: String = abc
scala> record(c)
res2: Float = 1.0
을 생성하는 데 사용할
저는 이런 종류의 데이터 구조가 매우 유용하다는 것을 알았습니다. 사례 클래스가 제공하는 것보다 더 많은 유연성이 필요할 때도 있지만, Map [String, Any]처럼 완전히 유형이 안전하지 않은 무언가에 의지하고 싶지는 않습니다. 이것은 좋은 중간계입니다.
편집 : 다른 옵션은 (이름, 유형) 쌍을 실제 키로 내부적으로 사용하는지도를 사용하는 것입니다. 값을 얻을 때 이름과 유형을 모두 제공해야합니다. 잘못된 유형을 선택하면 항목이 없습니다. 그러나 이것은 바이트를 넣고 int를 꺼내려고 할 때와 같이 오류가 발생할 가능성이 큽니다. 그래서 나는 이것이 좋은 생각이 아니라고 생각합니다.
import reflect.runtime.universe.TypeTag
class TypedMap[K](val inner:Map[(K, TypeTag[_]), Any]) extends AnyVal {
def updated[V](key:K, value:V)(implicit tag:TypeTag[V]) = new TypedMap[K](inner + ((key, tag) -> value))
def apply[V](key:K)(implicit tag:TypeTag[V]) = inner.apply((key, tag)).asInstanceOf[V]
def get[V](key:K)(implicit tag:TypeTag[V]) = inner.get((key, tag)).asInstanceOf[Option[V]]
}
object TypedMap {
def empty[K] = new TypedMap[K](Map.empty)
}
사용법 : 나는 마침내 내 경우에는 최선을 다했다 내 자신의 솔루션을 발견
scala> val x = TypedMap.empty[String].updated("a", 1).updated("b", "a string")
x: TypedMap[String] = [email protected]
scala> x.apply[Int]("a")
res0: Int = 1
scala> x.apply[String]("b")
res1: String = a string
// this is what happens when you try to get something out with the wrong type.
scala> x.apply[Int]("b")
java.util.NoSuchElementException: key not found: (b,Int)
가능한 복제본 http://stackoverflow.com/questions/4309835/scala-reflection/4310959 –