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

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

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

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

object StreetSecondary {
  //empty for now
}

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

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

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


ОБНОВЛЕНИЕ 1

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

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

B) Существует технический трюк, чтобы заставить tupled работать (спасибо drstevens): (StreetSecondary.apply _).tupled Хотя это решает конкретную проблему метода tupled, он все еще не точно или полностью не описывает, что scala компилятор предоставляет неявный объект-компаньон.

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

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

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

Ответ 1

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

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

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

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 выше,

вставляется в тело объекта (явная реализация остается сомнительной)

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

Ответ 2

Scala 2.11.0

Похоже, что scalac предопределяет функцию 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);
}

Ответ 3

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

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>