正确使用scala特征和类型

时间:2015-04-27 19:14:21

标签: scala

scala的新手并试图获得类系统的挂起。这是一个简单的设置:

sealed trait Shape{
  def sides:Int
}

final case class Square() extends Shape {
  def sides() = 4
}

final case class Triangle() extends Shape {
  def sides() = 3
}

现在,我想创建一个函数,它接收shape类型的任何类型,我们知道它将实现sides()方法,并使用该方法。

def someFunction(a: Shape)={
    val aShape = a()
    aShape.sides()
}

但这会在val aShape = a()遇到错误,因为没有类型a

我意识到在这个例子中,创建someFunction是过分的,因为可以直接从对象访问sides()。但我的主要问题是在someFunction的上下文中 - 我想将一个类传递给一个函数,并实例化该类的一个对象,然后对该对象做一些事情。谢谢你的帮助。

4 个答案:

答案 0 :(得分:1)

你想用这行代码做什么?您已经拥有shape,传入的名为a。只需删除该行,然后拨打a.sides()

在风格上,有几个问题。首先,类名应以大写字母开头。其次,sides似乎是一个不可变的属性,而不是一个变异的方法,所以它应该被声明和覆盖而没有括号。您的子类中还需要override个修饰符。最后,你可以不用空括号:{4}应该是4

答案 1 :(得分:1)

有几种方法可以做到这一点。一个是复杂的使用reflection,第二个是稍微简单一点,使用builder,第三个是最直接的用例。 只需将someFunction的定义更改为

即可
def someFunction(a: ()=>Shape)={
  val aShape = a()
  aShape.sides
}

所以someFunction(Square)返回4someFunction(Triangle)返回3。请注意这项工作仅适用于case class es,因为真实的,我们在这里传递的不是类本身,而是自动生成的companion object

但更常见的是没有必要定义类,你可以在除顶级事物之外的任何上下文中编写,就像

一样
def square() = new Shape{
  def sides() = 4
}

def triangle() = new Shape{
  def sides() = 3
}

下一步:具有空参数列表的方法通常读作具有副作用的方法。因此,定义类型

更方便
sealed trait Shape{
  def sides:Int
}

如果你定义你的构建器

def square = new Shape{
  def sides = 4
}

def triangle = new Shape{
  def sides = 3
}

你应该将它们用作someFunction(square _)告诉你,你要使用方法调用而不是它返回的值

最后一件事是:如果你真的需要代码,那就创建了一些对象,但它可能包含复杂的计算,资源处理或一些可能的异常,所以你想要保持它的执行,直到它真的需要,你可以使用等同于R的call-by-name parameters,我假设你熟悉

答案 2 :(得分:0)

除非shape具有apply功能,否则您无法在()对象上调用shape

如果您想将aShape分配给a,只需撰写val aShape = a

但由于我没有看到附加值,您可以直接在sides上调用a函数:

def someFunction(a:shape) = {
  val sides = a.sides
  // use sides
}

答案 3 :(得分:0)

这是你写的最接近的翻译:

sealed trait Shape {
  def sides: Int
}

case object Square extends Shape {
  override val sides = 4
}

case object Triangle extends Shape {
  override val sides = 3
}

def someFunction(a: Shape) =
  val shapeSides = a.sides

一些注意事项:

  • scala中的类应为CamelCase
  • 您的子类没有实例成员,因此您可以使用单例对象
  • 如果您拥有a: Shape,则表示aShape,并且您尚未定义任何可让您在其上调用()的内容。
  • 中只有一个表达式时,您可以省略大括号
  • 您可以使用def覆盖val(如果它是静态的)