Как передать неявный параметр из экземпляра? - PullRequest
0 голосов
/ 30 апреля 2011

Я пытаюсь определить класс, который будет иметь в качестве поля набор, и хотел бы иметь возможность манипулировать этим набором непосредственно из класса контейнера:

case class MyClass(prop: String) extends TraversableLike[Int,MyClass] {
   private def mySet: Set[Int]() = Set()

  override def foreach[U](f: Int => U) = data.foreach[U](f)

  override def newBuilder: Builder[Int, MyClass] =
    new ArrayBuffer[Int] mapResult (a => MyClass(prop, a.toSet))

  implicit def canBuildFrom: CanBuildFrom[MyClass, Int, MyClass] =
    new CanBuildFrom[MyClass, Int, MyClass] {
      def apply(): Builder[Int, MyClass] = newBuilder
      def apply(from: MyClass): Builder[Int, MyClass] = newBuilder
    }
}

Я бы хотел иметь возможность

var obj = MyClass("hello")
obj += 1
obj = obj map (_+1)

Первая инструкция (obj + = 1) работает, а вторая - нет. Проблема в том, что я не могу поместить свой неявный canBuildFrom в объект MyClass, потому что сборщик нуждается в информации, зависящей от экземпляра (в данном случае, поля prop).

Есть ли решение сделать мой неявный доступным и сохранить его зависимость экземпляра? Я бы не хотел, чтобы мой класс был изменчивым.

1 Ответ

4 голосов
/ 30 апреля 2011

Есть несколько проблем с вашим кодом:

  • Set[Int]() не является допустимым типом для mySet, вы должны удалить ()
  • member mySet должно быть val, а не def
  • , для которого вы вызываете методы apply (), которых не существует
  • , если вы хотите подключиться к иерархии коллекций наУровень прохождения, вы не получите методы, такие как + и производные +=.Если вы представляете набор, то это должен быть Set.

Вот пересмотренная попытка:

import mutable.Builder
import generic.CanBuildFrom

class MyClass private (val prop: String, private val mySet: Set[Int] = Set())
    extends immutable.Set[Int] with SetLike[Int, MyClass] {

  def -(elem: Int) = MyClass(prop, mySet - elem)
  def +(elem: Int) = MyClass(prop, mySet + elem)
  def contains(elem: Int) = mySet.contains(elem)
  def iterator = mySet.iterator

  override def empty: MyClass = MyClass(prop)

  override def stringPrefix = "MyClass(" + prop + ")"
}

object MyClass {

  def DefaultProp = "DefaultProp"

  def apply(prop: String, mySet: Set[Int] = Set()) = new MyClass(prop, mySet)

  def newBuilder(prop: String = DefaultProp): Builder[Int, MyClass] =
    Set.newBuilder[Int] mapResult (set => MyClass(prop, set))

  implicit def canBuildFrom: CanBuildFrom[MyClass, Int, MyClass] =
    new CanBuildFrom[MyClass, Int, MyClass] {
      def apply(): Builder[Int, MyClass] = newBuilder()
      def apply(from: MyClass): Builder[Int, MyClass] = newBuilder(from.prop)
    }

}

Тогда вы можете написать:

var obj = MyClass("hello")
obj += 1
println(obj) // prints MyClass(hello)(1)
obj = obj map (_ + 1)
println(obj) // prints MyClass(hello)(2)

Давайте рассмотрим, что:

MyClass теперь явным образом является неизменным набором с пользовательским представлением, объявленным в аргументах типа для SetLike.prop является публичным членом val;фактический набор, mySet, является частным значением.

Затем нам нужно реализовать четыре операции, на которые опирается Set, просто перенаправив их mySet.(Это похоже на то, что это может быть учтено. Для Seq есть класс SeqForwarder, который выполняет аналогичную работу, хотя я не смог найти SetForwarder, хотя).Наконец, мы предоставляем метод empty, на который также опирается встроенный унаследованный компоновщик.Наконец, переопределение stringPrefix включает более хорошее представление строки с «MyClass» и значением prop.

. Обратите внимание, что canBuildFrom object MyClass вызывает newBuilder, передавая prop изоригинальная коллекция, когда это возможно.Это означает, что большую часть времени вы можете сохранять это значение при отображении и т. Д. Для MyClass экземпляров.Нам нужно определить значение по умолчанию для prop, однако, поскольку CanBuildFrom s должен определить метод apply, который не сообщает, что такое исходная коллекция.(Вопрос: почему это на самом деле произошло?)

Наконец, наша реализация newBuilder больше не полагается на ArrayBuffer s, а непосредственно создает экземпляр Set, который будет обернут вашим новымMyClass instance.

Еще несколько ресурсов:

...