Как создать явный сопутствующий объект для класса 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>