Как создать явный сопутствующий объект для класса case, который ведет себя идентично замененному компилятору при условии неявного сопутствующего объекта?

У меня есть класс дела, определенный так:

case class StreetSecondary(designator: String, value: Option[String])

Затем я определяю явный объект-компаньон:

object StreetSecondary {
  //empty for now
}

Определение явного сопутствующего объекта StreetSecondary приводит к потере созданного компилятором "неявного сопутствующего объекта"; т.е. заменен без возможности доступа к версии, созданной компилятором. Например, tupled Метод доступен в классе Case StreetSecondary через этот неявный сопутствующий объект. Однако, как только я определю явный объект-компаньон, tupled метод "потерян".

Итак, что мне нужно для определения / добавления / изменения вышеуказанного явного сопутствующего объекта StreetSecondary, чтобы восстановить все функциональные возможности, утраченные при замене неявного сопутствующего объекта компилятором? И я хочу больше, чем просто tupled метод восстановлен. Я хочу, чтобы все функции (например, включая экстрактор /unapply) восстановлено.

Спасибо за любое направление / руководство, которое вы можете предложить.


ОБНОВЛЕНИЕ 1

Я сделал достаточно поиска, чтобы обнаружить несколько вещей:

A) Явный объект-компаньон должен быть определен ДО его класса case (по крайней мере, так обстоит дело в Eclipse Scala-IDE WorkSheet, и код не работает в WorkSheet IntelliJ IDE независимо от того, что будет первым).

Б) Есть технический прием, чтобы заставить tupled работать (спасибо drstevens) (StreetSecondary.apply _).tupled Пока это решает конкретные tupled проблема метода, он все еще не дает точного или полного описания того, что предоставляет компилятор scala в неявном объекте-компаньоне.

C) Наконец, явный объект-компаньон может быть определен для расширения функции, которая соответствует сигнатуре параметров первичного конструктора и возвращает экземпляр класса case. Это выглядит так:

object StreetSecondary extends ((String, Option[String]) => StreetSecondary) {
  //empty for now
}

Опять же, я все еще не уверен, точно или полностью описывает то, что предоставляет компилятор scala в неявном объекте-компаньоне.

3 ответа

Решение

При определении явного сопутствующего объекта для класса case (по состоянию на Scala 2.11) для полной замены предоставленной компилятором функциональности в потерянном неявном сопутствующем объекте базовый шаблон для явного сопутствующего объекта предъявляет два требования:

Требования:
1. Необходимо расширить определение функции, которая состоит из кортежа (точно совпадающего с типом и порядком параметров конструктора класса case), возвращающего тип класса case
2. Необходимо переопределить функцию toString, чтобы предоставить имя класса объекта (идентично тому, что у ассоциированного класса дел)

Вот оригинальный пример кода для "пустого" явного объекта-компаньона:

object StreetSecondary {
  //empty for now
}

И вот пример кода после реализации вышеуказанных требований:

object StreetSecondary extends ((String, Option[String]) => StreetSecondary) {
    //replace the toString implementation coming from the inherited class (FunctionN)
    override def toString =
      getClass.getName.split("""\$""").reverse.dropWhile(x => {val char = x.take(1).head; !((char == '_') || char.isLetter)}).head
}

Чтобы удовлетворить требование 1 выше, extends ((String, Option[String]) => StreetSecondary) вставляется сразу после имени объекта и перед первой фигурной скобкой.

Чтобы удовлетворить требование 2 выше, override def toString = getClass.getName.split("""\$""").reverse.dropWhile(x => {val char = x.take(1).head; !((char == '_') || char.isLetter)}).head вставляется в тело объекта (явная реализация остается сомнительной)

Глубокая благодарность @drstevens за то, что он опубликовал вывод javap, чтобы помочь мне обрести уверенность, два вышеуказанных шага - это все, что требуется для восстановления утраченной функциональности.

Scala 2.11.0

Похоже, что скаляр предопределяет tupled функция, когда вы не предоставляете дополнительные функции в компаньоне

case class BB(a: Int, b: Int)
object BB { }

case class AA(a: Int, b: Int)

object CC { }
case class CC(a: Int, b: Int)

приводит к следующему

public class AA implements scala.Product,scala.Serializable {
  public static scala.Option<scala.Tuple2<java.lang.Object, java.lang.Object>> unapply(AA);
  public static AA apply(int, int);
  public static scala.Function1<scala.Tuple2<java.lang.Object, java.lang.Object>, AA> tupled();
  public static scala.Function1<java.lang.Object, scala.Function1<java.lang.Object, AA>> curried();
  public int a();
  public int b();
  public AA copy(int, int);
  public int copy$default$1();
  public int copy$default$2();
  public java.lang.String productPrefix();
  public int productArity();
  public java.lang.Object productElement(int);
  public scala.collection.Iterator<java.lang.Object> productIterator();
  public boolean canEqual(java.lang.Object);
  public int hashCode();
  public java.lang.String toString();
  public boolean equals(java.lang.Object);
  public AA(int, int);
}

public final class AA$ extends scala.runtime.AbstractFunction2<java.lang.Object, java.lang.Object, AA> implements scala.Serializable {
  public static final AA$ MODULE$;
  public static {};
  public final java.lang.String toString();
  public AA apply(int, int);
  public scala.Option<scala.Tuple2<java.lang.Object, java.lang.Object>> unapply(AA);
  public java.lang.Object apply(java.lang.Object, java.lang.Object);
}

public class BB implements scala.Product,scala.Serializable {
  public static scala.Option<scala.Tuple2<java.lang.Object, java.lang.Object>> unapply(BB);
  public static BB apply(int, int);
  public int a();
  public int b();
  public BB copy(int, int);
  public int copy$default$1();
  public int copy$default$2();
  public java.lang.String productPrefix();
  public int productArity();
  public java.lang.Object productElement(int);
  public scala.collection.Iterator<java.lang.Object> productIterator();
  public boolean canEqual(java.lang.Object);
  public int hashCode();
  public java.lang.String toString();
  public boolean equals(java.lang.Object);
  public BB(int, int);
}

public final class BB$ implements scala.Serializable {
  public static final BB$ MODULE$;
  public static {};
  public BB apply(int, int);
  public scala.Option<scala.Tuple2<java.lang.Object, java.lang.Object>> unapply(BB);
}

public class CC implements scala.Product,scala.Serializable {
  public static scala.Option<scala.Tuple2<java.lang.Object, java.lang.Object>> unapply(CC);
  public static CC apply(int, int);
  public int a();
  public int b();
  public CC copy(int, int);
  public int copy$default$1();
  public int copy$default$2();
  public java.lang.String productPrefix();
  public int productArity();
  public java.lang.Object productElement(int);
  public scala.collection.Iterator<java.lang.Object> productIterator();
  public boolean canEqual(java.lang.Object);
  public int hashCode();
  public java.lang.String toString();
  public boolean equals(java.lang.Object);
  public CC(int, int);
}

public final class CC$ implements scala.Serializable {
  public static final CC$ MODULE$;
  public static {};
  public CC apply(int, int);
  public scala.Option<scala.Tuple2<java.lang.Object, java.lang.Object>> unapply(CC);
}

Почему вы думаете, что теряете их?

case class Person(name: String, age: Int)
object Person {
  def apply(): Person = new Person("Bob", 33)
}

val alice = Person("Alice", 20)
val bob   = Person()

Person.unapply(alice)    //Option[(String, Int)] = Some((Alice,20))
Person.unapply(Person()) //Option[(String, Int)] = Some((Bob,33))

Похоже, я все еще получил экстракторы.

В вашем случае у вас все еще есть все:

scala> StreetSecondary.unapply _
res10: StreetSecondary => Option[(String, Option[String])] = <function1>
Другие вопросы по тегам