简体   繁体   English

Scala Case Class Tupled

[英]Scala Case Class Tupled

How can I call the tupled method on this case class? 如何在此案例类中调用tupled方法?

case class(a: Int, b: String)(c: String, d: Int)

The reason why I have my case class like this is because I want to use only the first two parameters to be considered for equals and hashCode comparison! 我有这样的case类的原因是因为我想只使用前两个参数来考虑equals和hashCode比较!

So how can I properly call the tupled on such a case class? 那么如何在这样的案例类中正确调用tupled呢?

In short it does not seem like a good idea to use case classes this way. 简而言之,以这种方式使用案例类似乎不是一个好主意。 Here is an explanation. 这是一个解释。

Let's check the class declaration together with generated apply and unapply : 让我们一起检查类声明以及生成的applyunapply

scala> case class A(a: Int, b: String)(c: String, d: Int)
defined class A

scala> A.apply _
res0: (Int, String) => (String, Int) => A = <function2>

scala> A.unapply _
res1: A => Option[(Int, String)] = <function1>

You can see that although apply takes 4 arguments in total (curried), unapply discards second list. 您可以看到尽管apply总共需要4个参数(curried),但unapply会丢弃第二个列表。

Let's see if we can access members of the second list: 让我们看看我们是否可以访问第二个列表的成员:

scala> val a = A(1, "two")("three", 4)
a: A = A(1,two)

scala> a.a
res2: Int = 1

scala> a.c
<console>:11: error: value c is not a member of A
              a.c
                ^

... nope, not a regular way. ......不,不是常规方式。 Let's check couple more properties: 让我们来看看更多的房产:

scala> a.productArity
res4: Int = 2

scala> a.productIterator.toList
res5: List[Any] = List(1, two)

Ok, it seems like second argument list is pretty much ignored. 好吧,似乎第二个参数列表几乎被忽略了。 Let's dig in: 让我们深入研究:

scala> :javap A
...
  public int a();
    descriptor: ()I
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #16                 // Field a:I
         4: ireturn
...
  public java.lang.String b();
    descriptor: ()Ljava/lang/String;
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #21                 // Field b:Ljava/lang/String;
         4: areturn
...
  public boolean equals(java.lang.Object);
    descriptor: (Ljava/lang/Object;)Z
    flags: ACC_PUBLIC
     ... //mentions only a and b:....
        32: invokevirtual #32                 // Method a:()I
        35: aload         4
        37: invokevirtual #32                 // Method a:()I
        40: if_icmpne     88
        43: aload_0
        44: invokevirtual #35                 // Method b:()Ljava/lang/String;
        47: aload         4
        49: invokevirtual #35                 // Method b:()Ljava/lang/String;
...
  public A(int, java.lang.String, java.lang.String, int);                                                                 
    descriptor: (ILjava/lang/String;Ljava/lang/String;I)V                                                                 
    flags: ACC_PUBLIC                                                                                                     
    Code:                                                                                                                 
      stack=2, locals=5, args_size=5                                                                                      
         0: aload_0                                                                                                       
         1: iload_1                                                                                                       
         2: putfield      #16                 // Field a:I                                                                
         5: aload_0                                                                                                       
         6: aload_2                                                                                                       
         7: putfield      #21                 // Field b:Ljava/lang/String;                                               
        10: aload_0                                                                                                       
        11: invokespecial #100                // Method java/lang/Object."<init>":()V                                     
        14: aload_0                                                                                                       
        15: invokestatic  #106                // Method scala/Product$class.$init$:(Lscala/Product;)V                     
        18: return                                                                                                        
      LocalVariableTable:                                                                                                 
        Start  Length  Slot  Name   Signature                                                                             
            0      19     0  this   LA;                                                                                   
            0      19     1     a   I                                                                                     
            0      19     2     b   Ljava/lang/String;                                                                    
            0      19     3     c   Ljava/lang/String;                                                                    
            0      19     4     d   I                                                                                  

So there is no use of c and d in constructor or in equals. 所以在构造函数或equals中没有使用cd

You can still make second arg list params useful by prefixing them with val : 您仍然可以通过为val添加前缀来使第二个arg list params变得有用:

scala> case class B(a: Int, b: String)(val c: String, val d: Int)         
defined class B                                                           

scala> val b = B(1, "two")("three", 4)                                    
b: B = B(1,two)                                                           

scala> b.c                                                                
res6: String = three                                  

scala> b.d                                                                
res8: Int = 4    

Let's see how equality and hashcode works in this case: 让我们看看在这种情况下,相等和哈希码是如何工作的:

scala> val b2 = B(1, "two")("no the same", 555)
b2: B = B(1,two)

scala> b == b2
res10: Boolean = true

scala> b.hashCode
res13: Int = -1563217100

scala> b2.hashCode
res14: Int = -1563217100

Seems to work the way you want it to, which I personally don't like ;) 似乎按照你想要的方式工作,我个人不喜欢;)

For completeness, default pattern matching is still the way it was for class A : 为了完整性,默认模式匹配仍然是AA

scala> B.unapply _
res15: B => Option[(Int, String)] = <function1>

Scala language spec explains how it works here . Scala语言规范解释了它在这里的工作原理。

The formal parameters in the first parameter section of a case class are called elements; 案例类的第一个参数部分中的形式参数称为元素; they are treated specially. 他们受到特殊待遇。 First, the value of such a parameter can be extracted as a field of a constructor pattern. 首先,可以将这样的参数的值提取为构造函数模式的字段。 Second, a val prefix is implicitly added to such a parameter, unless the parameter carries already a val or var modifier. 其次,val前缀隐式添加到这样的参数中,除非该参数已经携带val或var修饰符。 Hence, an accessor definition for the parameter is generated. 因此,生成参数的访问器定义。

and

Every case class implicitly overrides some method definitions of class scala.AnyRef unless a definition of the same method is already given in the case class itself or a concrete definition of the same method is given in some base class of the case class different from AnyRef. 每个case类隐式覆盖scala.AnyRef类的一些方法定义,除非在case类本身中已经给出了相同方法的定义,或者在不同于AnyRef的case类的某个基类中给出了相同方法的具体定义。 In particular: 特别是:

  • Method equals : (Any)Boolean is structural equality, where two instances are equal if they both belong to the case class in question and they have equal (with respect to equals) constructor arguments ( restricted to the class's elements, ie, the first parameter section ). 方法等于 :(任意)布尔值是结构相等,其中两个实例相等,如果它们都属于所讨论的案例类并且它们具有相等(相对于等于)构造函数参数( 仅限于类的元素,即第一个参数)部分 )。
  • Method hashCode: Int computes a hash-code. 方法hashCode:Int计算哈希码。 If the hashCode methods of the data structure members map equal (with respect to equals) values to equal hash-codes, then the case class hashCode method does too. 如果数据结构成员的hashCode方法映射相等(相对于equals)值为相等的哈希码,那么case类hashCode方法也是如此。
  • Method toString: String returns a string representation which contains the name of the class and its elements. 方法toString:String返回一个字符串表示形式,其中包含类及其元素的名称。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM