9

我有一个这样定义的案例类:

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

然后我定义了一个显式的伴随对象:

object StreetSecondary {
  //empty for now
}

定义显式伴随对象 StreetSecondary 的行为导致编译器生成的“隐式伴随对象”丢失;即替换为无法访问编译器生成的版本。例如,该tupled方法可通过此隐式伴随对象在案例类 StreetSecondary 上使用。但是,一旦我定义了显式伴随对象,该tupled方法就会“丢失”。

那么,我需要对上述 StreetSecondary 显式伴随对象进行定义/添加/更改,以重新获得因替换编译器提供的隐式伴随对象而丢失的所有功能?而且我想要的不仅仅是tupled恢复的方法。unapply我希望恢复 所有功能(例如,包括 extractor/ )。

感谢您提供的任何方向/指导。


更新 1

我已经做了足够的搜索以发现几件事:

A)显式伴随对象必须在其案例类之前定义(至少在 Eclipse Scala-IDE WorkSheet 中是这种情况,并且代码在 IntelliJ IDE 的 WorkSheet 中不起作用,无论哪个先出现)。

B)有一个强制tupled工作的技术技巧(谢谢 drstevens):(StreetSecondary.apply _).tupled虽然这解决了特定的tupled方法问题,但它仍然不能准确或完整地描述 scala 编译器在隐式伴随对象中提供的内容。

C) 最后,可以定义显式伴随对象来扩展一个函数,该函数匹配主构造函数的参数签名并返回案例类的实例。它看起来像这样:

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

同样,我仍然不能准确或完整地描述 scala 编译器在隐式伴随对象中提供的内容。

4

3 回答 3

5

在为案例类定义显式伴随对象时(从 Scala 2.11 开始),要完全替换丢失的隐式伴随对象中的编译器提供的功能,显式伴随对象的基本模板有两个要求:

要求:
1. 必须扩展一个函数定义,该函数定义包含一个返回案例类类型的元组(完全匹配案例类构造函数参数的类型和顺序)
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)在对象名称之后和第一个花括号之前插入。

为了满足上面override def toString = getClass.getName.split("""\$""").reverse.dropWhile(x => {val char = x.take(1).head; !((char == '_') || char.isLetter)}).head的要求 2,插入到对象的主体中(显式实现仍然值得怀疑)

非常感谢 @drstevens 发布 javap 输出以帮助我获得信心,以上两个步骤是恢复丢失的功能所需的全部。

于 2014-08-20T20:45:32.320 回答
3

斯卡拉 2.11.0

tupled当您未在伴侣中提供其他功能时,看起来 scalac 正在预定义该功能

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);
}
于 2014-08-19T22:00:10.147 回答
1

为什么你会认为你正在失去他们?

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>
于 2014-08-19T21:05:27.370 回答