Scala - defining own infix operators

纵饮孤独 提交于 2019-12-31 01:55:11

问题


Methods taking a single argument can be written as an infix operators in Scal. I.e. adding *(other:C) = foo(this, other) to class C, will allow us to write c1 * c2 instead of foo(c1,c2). But is there a way to define infix operators on existing classes that you cannot modify?

E.g. if I wanted to write c1 + c2 instead of xor(c1,c2), where c1,c2:Array[Byte], I obviously cannot modify the Array-Class.

I found this and tried

implicit class Bytearray(a1:Array[Byte]) extends Anyval {
    def +(a2:Array[Byte]) = xor(a1,a2)
}

But that doesn't seem to work (c1 + c2).

Type mismatch, expected:String, actual:Array[Byte]

I thought that perhaps the issue was my using +, so I exchanged it for xor but c1 xor c2 only lead to

Cannot resolve symbol xor

Any suggestions?

UPDATE

Interesting. I had a class Foo with an object Foo defined below it, containing the implicit class. This lead to the aforementioned errors.

However, deleting the object and instead putting the implicit class into a trait BytearrayHandling and then extending it (class Foo extends BytearrayHandling) seems to work. Why is that?


回答1:


It should be straight forward with the normal declaration of extension methods:

implicit class ByteArrayOps(private val a1: Array[Byte]) extends AnyVal {
  def + (a2: Array[Byte]): Array[Byte] = 
    (a1 zip a2).map { case (x, y) => (x ^ y).toByte }
}

"foo".getBytes + "bar".getBytes  // Array(4, 14, 29)

However be aware that sometimes you will run into this:

Type mismatch, expected:String, actual: X

This is because of an implicit conversion kicking in that allows you to + anything by converting it to a String. I have given up trying to understand how to deactivate it. It will finally go in Scala 2.12 if I'm not mistaken.

As eugener pointed out, this error message may indicate that you haven't actually imported your extension method (implicit conversion). For example:

object MyStuff {
  implicit class ByteArrayOps(private val a1: Array[Byte]) extends AnyVal {
    def + (a2: Array[Byte]): Array[Byte] = 
      (a1 zip a2).map { case (x, y) => (x ^ y).toByte }
  }
}

"foo".getBytes + "bar".getBytes  // error

gives:

<console>:14: error: type mismatch;
 found   : Array[Byte]
 required: String
              "foo".getBytes + "bar".getBytes
                                     ^

because of this Predef conversion. After you import MyStuff.ByteArrayOps, it works.




回答2:


You can do something like:

class ByteArray(self: Array[Byte]) {
  def +(other: Array[Byte]) = Array[Byte](1, 2, 3) // replace with your code
}

implicit def byteArrayPlus(self: Array[Byte]) = new ByteArray(self)

Array[Byte](0, 1, 2) + Array[Byte](0, 2, 3)

the last line of which should yield Array(1, 2, 3).



来源:https://stackoverflow.com/questions/31221462/scala-defining-own-infix-operators

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!