代码之家  ›  专栏  ›  技术社区  ›  Metropolis

如何实现具有混合但受限制的值类型的键、值对的集合

  •  1
  • Metropolis  · 技术社区  · 6 年前

    这里的一个用例是想象一个配置对象,它是一个键值对的集合。

    我想创建一个类型来表示这个键、值对的集合。我也希望这些价值观是多种多样的。此外,我希望将这些键和值对保存在一个集合中,尽管这些值属于不同的类型。但我根本不想让这些值按任何类型排列。最后,我希望能够恢复给定密钥的值。(加分,我想确保钥匙是唯一的)

    类似于:

    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 方法以返回基础值而不是包装值?

    一种方法是这样写getter:

    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] 似乎错了。要使用getter,您需要提前知道值的类型。那也许不错,但可能会很麻烦。

    我也找不到一个可以接受的使用类型类的方法,但是我承认我对编写类型类没有很深的经验。

    0 回复  |  直到 6 年前