【问题标题】:Utility methods for operating on custom scala class用于操作自定义 scala 类的实用方法
【发布时间】:2014-10-12 00:49:50
【问题描述】:

我想在 Scala 中定义一个适用于自定义类的运算符。类似于scala的Array utility methods,比如Array concatenation:

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

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

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

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

提供一个更具体的例子,假设 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()}
  } 
}

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

【问题讨论】:

  • 1.我糊涂了。问题是什么?
  • 2.这三个代码示例看起来都非常不同,而且完全没有相似之处。
  • 3.你的最后一句话准确地描述了你做了什么。
  • 我假设您的意思是您想要第三个 sn-p 的功能,以及第二个的语法?看我的回答
  • 我给了你第一个的语法和第三个和第二个的组合功能。我回答的最后两行看起来像你的前两行。

标签: scala oop abstract-class


【解决方案1】:

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

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

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

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 {}

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

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] = ...
}

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

【讨论】:

  • 这回答了上述问题。我最终在一个定义了原始类集合的不同抽象类中稍微不同地实现它,类似于您的第一个建议。
【解决方案2】:

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

然后,我们可以定义一个对象,它接受任何两个相同类型的对象,只要它们包含“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
}

现在我们可以创建任何扩展 OpTrait 和 class 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)

由于 OpTrait 是在泛型类型上参数化的,因此您实际上可以在不同类型之间定义操作(但只能以一种顺序)。您还可以通过使其协变来定义对 MyClass 和 MyClass 的子类型起作用的操作,但仅当参数处于一个顺序时。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-08-28
    • 1970-01-01
    • 2013-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-20
    • 2021-09-17
    相关资源
    最近更新 更多