Matching with custom combinations/operators

前端 未结 3 617
我在风中等你
我在风中等你 2021-01-12 20:29

I know that you can do matching on lists in a way like

val list = List(1,2,3)
list match {
  case head::tail => head
  case _ => //whatever
}
         


        
3条回答
  •  野的像风
    2021-01-12 20:58

    Pattern matching takes the input and decomposes it with an unapply function. So in your case, unapply(4) would have to return the two numbers that sum to 4. However, there are many pairs that sum to 4, so the function wouldn't know what to do.

    What you need is for the 2 to be accessible to the unapply function somehow. A special case class that stores the 2 would work for this:

    case class Sum(addto: Int) {
        def unapply(i: Int) = Some(i - addto)
    }
    
    val Sum2 = Sum(2)
    val Sum2(x) = 5  // x = 3
    

    (It would be nice to be able to do something like val Sum(2)(y) = 5 for compactness, but Scala doesn't allow parameterized extractors; see here.)

    [EDIT: This is a little silly, but you could actually do the following too:

    val `2 +` = Sum(2)
    val `2 +`(y) = 5  // y = 3
    

    ]

    EDIT: The reason the head::tail thing works is that there is exactly one way to split the head from the tail of a list.

    There's nothing inherently special about :: versus +: you could use + if you had a predetermined idea of how you wanted it to break a number. For example, if you wanted + to mean "split in half", then you could do something like:

    object + {
        def unapply(i: Int) = Some(i-i/2, i/2)
    }
    

    and use it like:

    scala> val a + b = 4
    a: Int = 2
    b: Int = 2
    
    scala> val c + d = 5
    c: Int = 3
    d: Int = 2
    

    EDIT: Finally, this explains that, when pattern matching, A op B means the same thing as op(A,B), which makes the syntax look nice.

提交回复
热议问题