这里的一个用例是想象一个配置对象,它是键-值对的集合。
我想创建一个表示此键,值对集合的类型。而且我也想让值具有不同的类型。此外,尽管这些值是不同类型的,但我还是希望将这些键,值对保留在一个集合中。但是我根本不想允许任何类型的值。最后,我希望能够恢复给定键的值。 (奖励积分,我想确保键是唯一的)
类似的东西:
trait Property
case class SProperty(name: String, value:String) extends Property
case class DProperty(name: String, value:Double) extends Property
case class IProperty(name: String, value:Int) extends Property
case class Properties(props: List[Property]) {
def getValueByName(name: String) = {
props.find(p => p.name == name).map(p => p.value)
}
}
这行得通,但是它创建了一个难看的API。例如:
val properties = Properties(
List(
Property("some name", "some value"),
Property("another name", "another value")
)
)
如果我的测试可以检查:
properties.getValueByName("some name").getOrElse(None) shouldBe "some value"
测试将失败,并显示
SProperty("some value") is not equal to "some value"
我考虑使用无形的HList,但是这将允许Properties
接受任何类型。我只希望集合中的Property
类型,并且我希望其中的值限于类型String | Double | Int
。
是否有更好的方法来定义键值对的集合,该键值对允许一组特定的值类型,并且可以为我提供.get
方法?
是否有更好的方法来定义我的getValueByName
方法,使其返回基础值而不是包装值?
一种方法是这样编写吸气剂:
def getValueByName[T](name: String): Option[Any] = {
Properties.find(p => p.name == name).map {
case Property(_, SProperty(v)) => Some(v)
case Property(_, DProperty(v)) => Some(v)
case Property(_, IProperty(v)) => Some(v)
case _ => None
}
}
但这在修改代码以添加允许属性值的新类型的地方开始很多。返回Option[Any]
似乎是错误的。要使用吸气剂,您需要提前知道值的类型。那可能很好,但是可能很麻烦。
我也无法找到使用类型类的可接受方法,但是我承认我对编写类型类没有很深的经验。