Как получить Map-like сахар в другом конструкторе - PullRequest
2 голосов
/ 06 января 2011

Что мне нужно - это класс XI, который можно построить с помощью карты, которая переносит строки в другие строки или карты, которые переносят строки в строки, а затем произвольное число других экземпляров X. Я знаю, что могу сделать это:

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

но это выглядит не очень Scala-ish ("Scalish"? "Scalerific"? "Scalogical"?) Я хотел бы иметь возможность сделать следующее:

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

Я знаю, что могу избавиться от «нового» с помощью объекта-компаньона, и я уверен, что могу посмотреть Scala varargs. То, что я хотел бы знать, это:

  1. Как я могу использовать -> (или некоторый похожий правдоподобный оператор) для конструирования элементов, которые должны быть превращены в карту в конструкции?
  2. Как я могу определить одну карту, чтобы она могла выполнять переключение по типу Option между двумя очень разнородными типами или превращалась в рекурсивное дерево, где каждый (именованный) узел указывает либо на лист в форме строки, либо узел похож на себя?

Рекурсивная версия действительно мне нравится, потому что, хотя она и не решает проблему, с которой я на самом деле сталкиваюсь сегодня, она аккуратно отображается в подмножество JSON, содержащее только объекты и строки (без чисел или массивов).

Любая помощь, как всегда, очень ценится.

Ответы [ 3 ]

3 голосов
/ 06 января 2011

-> - это просто синтаксический сахар для создания пары (A, B), так что вы тоже можете его использовать.Map объект принимает различные пары:

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

Сначала вы должны проверить Архитектура коллекций Scala , если вы заинтересованы в имитации коллекцийlibrary.

Сказав это, я не думаю, что подпись, которую вы предложили для Person, выглядит как Map, потому что она ожидает переменный аргумент, но children не являются непрерывными с другими (String, A)тема.Если вы скажете "child1" -> Alice и отдельно сохраните Alice, вы можете определить:

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

в сопутствующем объекте.Если Any слишком свободно, вы можете определить PersonElem trait,

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

и неявное преобразование между String, Map[String, String], Person и т. Д. В PersonElem.

1 голос
/ 06 января 2011

Это приводит вас почти туда.Есть еще карта, от которой мне нелегко избавиться.

Основной подход состоит в том, чтобы иметь несколько искусственных типов параметров, которые наследуются от общего типа.Таким образом, метод apply просто принимает одно значение.

Используя метод неявного преобразования, я избавляюсь от уродливых конструкторов для типов параметров

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)
    } }
0 голосов
/ 06 января 2011

Вот один из способов:

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...