如何在另一个构造函数中获取类似 Map 的糖

发布于 2024-10-10 17:38:09 字数 825 浏览 1 评论 0原文

需要是一个类XI,它可以用一个将字符串放入其他字符串的映射或将字符串放入字符串的映射,然后构造任意数量的其他X实例。由于我对Scala,我知道我可以做到这一点:

class Person (stringParms : Map[String, String],
        mapParms : Map[String, Map[String, String]],
        children : List[X]) {
}

但这看起来不太像 Scala(“Scalish”?“Scalerific”?“Scaological”?)我希望能够做到以下几点:

Person bob = Person("name" -> "Bob", "pets" -> ("cat" -> "Mittens", "dog" -> "Spot"), "status" -> "asleep", 
        firstChild, secondChild)

我知道我可以通过使用伴生对象摆脱“新”,我确信我可以查看 Scala 可变参数。我想知道的是:

  1. 我如何使用 -> (或一些类似合理的运算符)来构造要在构造中制作成 Map 的元素?
  2. 我如何定义一个映射,以便它可以在两种完全不同的类型之间进行类似选项的切换,或者成为递归树,其中每个(命名)节点指向字符串形式的叶子或像它自己一样的另一个节点?

递归版本确实很吸引我,因为虽然它没有解决我今天实际遇到的问题,但它巧妙地映射到仅包含对象和字符串(没有数字或数组)的 JSON 子集。

一如既往,非常感谢任何帮助。

What I need is a class X I can construct with a Map that takes Strings into either other Strings or Maps that take Strings into Strings, and then an arbitrary number of other instances of X. With my limited grasp of Scala, I know I can do this:

class Person (stringParms : Map[String, String],
        mapParms : Map[String, Map[String, String]],
        children : List[X]) {
}

but that doesn't look very Scala-ish ("Scalish"? "Scalerific"? "Scalogical"?) I'd like to be able to do is the following:

Person bob = Person("name" -> "Bob", "pets" -> ("cat" -> "Mittens", "dog" -> "Spot"), "status" -> "asleep", 
        firstChild, secondChild)

I know I can get rid of the "new" by using the companion object and I'm sure I can look Scala varargs. What I'd like to know is:

  1. How I can use -> (or some similarly plausible operator) to construct elements to be made into a Map in the construction?
  2. How I can define a single map so either it can do an Option-like switch between two very disparate types or becomes a recursive tree, where each (named) node points to either a leaf in the form of a String or another node like itself?

The recursive version really appeals to me because, although it doesn't address a problem I actually have today, it maps neatly into a subset of JSON containing only objects and strings (no numbers or arrays).

Any help, as always, greatly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

生死何惧 2024-10-17 17:38:09

-> 只是一个语法糖来组成一对 (A, B),因此您也可以使用它。 Map 对象接受成对的 vararg:

def apply [A, B] (elems: (A, B)*) : Map[A, B]

您应该首先查看 架构Scala Collections(如果您有兴趣模仿集合库)。

话虽如此,我不认为您为 Person 提出的签名看起来像 Map,因为它需要变量参数,但 children 却不是与其他 (String, A) 主题连续。如果你说“child1”-> Alice,并在内部单独存储Alice,您可以

def apply(elems: (String, Any)*): Person

在伴随对象中定义:。如果 Any 太宽松,您可以定义 PersonElem 特征,

def apply(elems: (String, PersonElem)*): Person

以及 StringMap[String, String] 之间的隐式转换code>、Person 等到 PersonElem

-> is just a syntactic sugar to make a pair (A, B), so you can use it too. Map object takes a vararg of pairs:

def apply [A, B] (elems: (A, B)*) : Map[A, B]

You should first check out The Architecture of Scala Collections if you're interested in mimicking the collections library.

Having said that, I don't think the signature you proposed for Person looks like Map, because it expects variable argument, yet children are not continuous with the other (String, A) theme. If you say "child1" -> Alice, and internally store Alice seperately, you could define:

def apply(elems: (String, Any)*): Person

in the companion object. If Any is too loose, you could define PersonElem trait,

def apply(elems: (String, PersonElem)*): Person

and implicit conversion between String, Map[String, String], Person, etc to PersonElem.

不知在何时 2024-10-17 17:38:09

这让你几乎成功了。还有一张地图我无法轻易摆脱。

基本方法是拥有一个有点人为的参数类型,它继承自通用类型。这样,apply 方法只需要一个 vararg。

使用隐式转换方法,我摆脱了参数类型的丑陋构造函数

case class Child

case class Person(stringParms: Map[String, String],
    mapParms: Map[String, Map[String, String]],
    children: List[Child]) { }

sealed abstract class PersonParameter 
case class MapParameter(tupel: (String, Map[String, String])) extends PersonParameter 
case class StringParameter(tupel: (String, String)) extends PersonParameter 
case class ChildParameter(child: Child) extends PersonParameter

object Person {
    def apply(params: PersonParameter*): Person = {

        var stringParms = Map[String, String]()
        var mapParms = Map[String, Map[String, String]]()
        var children = List[Child]()
        for (p ← params) {
            p match {
                case StringParameter(t) ⇒ stringParms += t
                case MapParameter(t) ⇒ mapParms += t
                case ChildParameter(c) ⇒ children = c :: children
            }
        }
        new Person(stringParms, mapParms, children)
    }
    implicit def tupel2StringParameter(t: (String, String)) = StringParameter(t)
    implicit def child2ChildParameter(c: Child) = ChildParameter(c)
    implicit def map2MapParameter(t: (String, Map[String, String])) = MapParameter(t)

    def main(args: Array[String]) {
        val firstChild = Child()
        val secondChild = Child()
        val bob: Person = Person("name" -> "Bob","pets" -> Map("cat" -> "Mittens", "dog" -> "Spot"),"status"
-> "asleep", 
        firstChild, secondChild)

        println(bob)
    } }

This gets you almost there. There is still a Map I don't get easily rid of.

The basic approach is to have a somewhat artificial parameter types, which inherit from a common type. This way the apply method just takes a single vararg.

Using implicit conversion method I get rid of the ugly constructors for the parameter types

case class Child

case class Person(stringParms: Map[String, String],
    mapParms: Map[String, Map[String, String]],
    children: List[Child]) { }

sealed abstract class PersonParameter 
case class MapParameter(tupel: (String, Map[String, String])) extends PersonParameter 
case class StringParameter(tupel: (String, String)) extends PersonParameter 
case class ChildParameter(child: Child) extends PersonParameter

object Person {
    def apply(params: PersonParameter*): Person = {

        var stringParms = Map[String, String]()
        var mapParms = Map[String, Map[String, String]]()
        var children = List[Child]()
        for (p ← params) {
            p match {
                case StringParameter(t) ⇒ stringParms += t
                case MapParameter(t) ⇒ mapParms += t
                case ChildParameter(c) ⇒ children = c :: children
            }
        }
        new Person(stringParms, mapParms, children)
    }
    implicit def tupel2StringParameter(t: (String, String)) = StringParameter(t)
    implicit def child2ChildParameter(c: Child) = ChildParameter(c)
    implicit def map2MapParameter(t: (String, Map[String, String])) = MapParameter(t)

    def main(args: Array[String]) {
        val firstChild = Child()
        val secondChild = Child()
        val bob: Person = Person("name" -> "Bob","pets" -> Map("cat" -> "Mittens", "dog" -> "Spot"),"status"
-> "asleep", 
        firstChild, secondChild)

        println(bob)
    } }
戴着白色围巾的女孩 2024-10-17 17:38:09

这是一种方法:

sealed abstract class PersonParam
object PersonParam {
    implicit def toTP(tuple: (String, String)): PersonParam = new TupleParam(tuple)
    implicit def toMap(map: (String, Map[String, String])): PersonParam = new MapParam(map)
    implicit def toSP(string: String): PersonParam = new StringParam(string)
}

class TupleParam(val tuple: (String, String)) extends PersonParam
class MapParam(val map: (String, Map[String, String])) extends PersonParam
class StringParam(val string: String) extends PersonParam

class Person(params: PersonParam*) {
    val stringParams = Map(params collect { case parm: TupleParam => parm.tuple }: _*)
    val mapParams = Map(params collect { case parm: MapParam => parm.map }: _*)
    val children = params collect { case parm: StringParam => parm.string } toList
}

用法:

scala> val bob = new Person("name" -> "Bob",
     | "pets" -> Map("cat" -> "Mittens", "dog" -> "Spot"),
     | "status" -> "asleep",
     | "little bob", "little ann")
bob: Person = Person@5e5fada2

scala> bob.stringParams
res11: scala.collection.immutable.Map[String,String] = Map((name,Bob), (status,asleep))

scala> bob.mapParams
res12: scala.collection.immutable.Map[String,Map[String,String]] = Map((pets,Map(cat -> Mittens, dog -> Spot)))

scala> bob.children
res13: List[String] = List(little bob, little ann)

Here's one way:

sealed abstract class PersonParam
object PersonParam {
    implicit def toTP(tuple: (String, String)): PersonParam = new TupleParam(tuple)
    implicit def toMap(map: (String, Map[String, String])): PersonParam = new MapParam(map)
    implicit def toSP(string: String): PersonParam = new StringParam(string)
}

class TupleParam(val tuple: (String, String)) extends PersonParam
class MapParam(val map: (String, Map[String, String])) extends PersonParam
class StringParam(val string: String) extends PersonParam

class Person(params: PersonParam*) {
    val stringParams = Map(params collect { case parm: TupleParam => parm.tuple }: _*)
    val mapParams = Map(params collect { case parm: MapParam => parm.map }: _*)
    val children = params collect { case parm: StringParam => parm.string } toList
}

Usage:

scala> val bob = new Person("name" -> "Bob",
     | "pets" -> Map("cat" -> "Mittens", "dog" -> "Spot"),
     | "status" -> "asleep",
     | "little bob", "little ann")
bob: Person = Person@5e5fada2

scala> bob.stringParams
res11: scala.collection.immutable.Map[String,String] = Map((name,Bob), (status,asleep))

scala> bob.mapParams
res12: scala.collection.immutable.Map[String,Map[String,String]] = Map((pets,Map(cat -> Mittens, dog -> Spot)))

scala> bob.children
res13: List[String] = List(little bob, little ann)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文