用于操作自定义scala类的实用程序方法

时间:2020-12-29 21:01:48

I'd like to define an operator that works on a custom class in Scala. Similar to scala's Array utility methods, such as Array concatenation:

我想定义一个在Scala中处理自定义类的运算符。与scala的Array实用程序方法类似,例如Array concatenation:

val (a, b) = (new Array[Int](4), new Array[Int](3))
val c = Array.concat(a, b)

I'd like to define an operator vaguely as follows:

我想模糊地定义一个运算符如下:

class MyClass {
  def op():MyClass = {
     // for instance,, 
     return new MyClass();
  }
}

to be invoked, like val x = MyClass.op()

被调用,如val x = MyClass.op()

To provide a more concrete example, suppose that MyClass is an extension of MyAbstractClass

为了提供更具体的示例,假设MyClass是MyAbstractClass的扩展

// Provided as a utility for the more relevant code below. 
def randomBoolean():Boolean = {
  val randomInt = Math.round(Math.random()).toInt
  if (randomInt == 1 ) return true;
  else return false;
}

abstract class MyAbstractClass[T](size:Int) {
  val stuff = new Array[T](size)
  def randomClassStuff():Array[T]
}

class MyClass(size:Int) extends MyAbstractClass[Boolean](size) {
  def randomClassStuff():Array[Boolean] = {
    return new Array[Boolean](size) map {x => randomBoolean()}
  } 
}

I realize that I could define an object called MyClass with a function called randomClassStuff defined in there, but I'd rather utilize abstract classes to require that extensions of the abstract class provide a method that creates random stuff specific to that class.

我意识到我可以定义一个名为MyClass的对象,其中定义了一个名为randomClassStuff的函数,但我宁愿利用抽象类来要求抽象类的扩展提​​供一种方法来创建特定于该类的随机内容。

2 个解决方案

#1


0  

Using your first example, to be able to invoke an operator concat as Array.concat(), there needs to exist an object called Array somewhere in scope that has concat as a method. The simplest way to do that would be:

使用您的第一个示例,为了能够将操作符concat调用为Array.concat(),需要在范围内存在一个名为Array的对象,该对象具有concat作为方法。最简单的方法是:

object Array {
  def concat[T](xs: Array[T], ys: Array[T]): Array[T] = ...
}

Otherwise you could define an abstract class (or trait) and have the object inherit it:

否则,您可以定义一个抽象类(或特征)并让对象继承它:

abstract class ArrayUtils {
  // Implemented here
  def concat[T](xs: Array[T], ys: Array[T]): Array[T] = ...
}

//Define the object
object Arrays extends ArrayUtils

// Or as a val
val Array = new ArrayUtils {}

Alternatively the abstract class could just define the operator and the object would implement it:

或者,抽象类可以只定义运算符,对象将实现它:

abstract class ArrayUtils {
  // Defined here
  def concat[T](xs: Array[T], ys: Array[T]): Array[T]
}

object Arrays extends ArrayUtils {
  // Implemented here
  def concat[T](xs: Array[T], ys: Array[T]): Array[T] = ...
}

The last is probably closest to what you wanted.

最后一个可能最接近你想要的。

#2


0  

We can define an OpTrait that declares a method ("op") that operates on something of the same type, so that any class that implements that method can only take in arguments of the same type as the class it was declared in.

我们可以定义一个OpTrait来声明一个对相同类型的东西进行操作的方法(“op”),这样任何实现该方法的类只能接受与它声明的类相同类型的参数。

Then, we can define an object that takes any two objects of the same type, as long as they include the "op" method (by mixing in the OpTrait--you can alternatively use structural typing, but that's slow and less organized):

然后,我们可以定义一个对象,它接受任何两个相同类型的对象,只要它们包含“op”方法(通过在OpTrait中混合 - 您也可以使用结构类型,但这很慢且组织性较差):

trait OpTrait[B] {
    def op(b: B)
}

object MyClass {
    def op[A <: OpTrait[A]](x: A, y: A) = x.op(y) // x op y
}

Now we can create any class that extends OpTrait and class MyClass.op(obj1, obj2):

现在我们可以创建任何扩展OpTrait和类MyClass.op(obj1,obj2)的类:

// example of usage
class MyClass(val num: Int) extends OpTrait[MyClass] {
    def op(b: MyClass) = new MyClass(num + b.num)
}

val (a,b) = (new MyClass(5), new MyClass(6))
MyClass.op(a, b) // should return MyClass(11)

Since the OpTrait is parameterized on a generic type, you can actually define an operation between different types (but only in one order). You can also define the operation to work on MyClass and a subtype of MyClass by making it covariant, but only when arguments are in one order.

由于OpTrait是在泛型类型上参数化的,因此您实际上可以定义不同类型之间的操作(但只能在一个订单中)。您还可以通过使其变为协变来定义在My​​Class上工作的操作和MyClass的子类型,但仅当参数在一个顺序中时才可以。

#1


0  

Using your first example, to be able to invoke an operator concat as Array.concat(), there needs to exist an object called Array somewhere in scope that has concat as a method. The simplest way to do that would be:

使用您的第一个示例,为了能够将操作符concat调用为Array.concat(),需要在范围内存在一个名为Array的对象,该对象具有concat作为方法。最简单的方法是:

object Array {
  def concat[T](xs: Array[T], ys: Array[T]): Array[T] = ...
}

Otherwise you could define an abstract class (or trait) and have the object inherit it:

否则,您可以定义一个抽象类(或特征)并让对象继承它:

abstract class ArrayUtils {
  // Implemented here
  def concat[T](xs: Array[T], ys: Array[T]): Array[T] = ...
}

//Define the object
object Arrays extends ArrayUtils

// Or as a val
val Array = new ArrayUtils {}

Alternatively the abstract class could just define the operator and the object would implement it:

或者,抽象类可以只定义运算符,对象将实现它:

abstract class ArrayUtils {
  // Defined here
  def concat[T](xs: Array[T], ys: Array[T]): Array[T]
}

object Arrays extends ArrayUtils {
  // Implemented here
  def concat[T](xs: Array[T], ys: Array[T]): Array[T] = ...
}

The last is probably closest to what you wanted.

最后一个可能最接近你想要的。

#2


0  

We can define an OpTrait that declares a method ("op") that operates on something of the same type, so that any class that implements that method can only take in arguments of the same type as the class it was declared in.

我们可以定义一个OpTrait来声明一个对相同类型的东西进行操作的方法(“op”),这样任何实现该方法的类只能接受与它声明的类相同类型的参数。

Then, we can define an object that takes any two objects of the same type, as long as they include the "op" method (by mixing in the OpTrait--you can alternatively use structural typing, but that's slow and less organized):

然后,我们可以定义一个对象,它接受任何两个相同类型的对象,只要它们包含“op”方法(通过在OpTrait中混合 - 您也可以使用结构类型,但这很慢且组织性较差):

trait OpTrait[B] {
    def op(b: B)
}

object MyClass {
    def op[A <: OpTrait[A]](x: A, y: A) = x.op(y) // x op y
}

Now we can create any class that extends OpTrait and class MyClass.op(obj1, obj2):

现在我们可以创建任何扩展OpTrait和类MyClass.op(obj1,obj2)的类:

// example of usage
class MyClass(val num: Int) extends OpTrait[MyClass] {
    def op(b: MyClass) = new MyClass(num + b.num)
}

val (a,b) = (new MyClass(5), new MyClass(6))
MyClass.op(a, b) // should return MyClass(11)

Since the OpTrait is parameterized on a generic type, you can actually define an operation between different types (but only in one order). You can also define the operation to work on MyClass and a subtype of MyClass by making it covariant, but only when arguments are in one order.

由于OpTrait是在泛型类型上参数化的,因此您实际上可以定义不同类型之间的操作(但只能在一个订单中)。您还可以通过使其变为协变来定义在My​​Class上工作的操作和MyClass的子类型,但仅当参数在一个顺序中时才可以。