【问题标题】:Is this the correct way of translating Java interface into Scala?这是将 Java 接口转换为 Scala 的正确方法吗?
【发布时间】:2012-01-27 12:28:07
【问题描述】:

我开始学习 Scala,我会做一个简单的交叉编译器。

我将支持一小部分指令,例如打印。

注意:代码 sn-ps 未经测试或编译。
这是我在 JAVA 中要做的事情。

public interface Compiler{
 String getPrintInstruction();
}

public class JavaCompiler implements Compiler{
 public String getPrintInstruction(){
  return "System.out.print(arg0);"
 }
}

public class ScalaCompiler implements Compiler{
 public String getPrintInstruction(){
  return "print(arg0);"
 }
}

下面的sn-p是正确的“Scala方式”吗?

trait Compiler {
  var printInstruction: String
}
class JavaCompiler extends Compiler {
  var printInstruction = "System.out.print(arg0);"
}
class ScalaCompiler extends Compiler {
  var printInstruction = "print(arg0);"
}

编辑:

我将把我的第二个问题移到一个新线程。

【问题讨论】:

  • 你声明的变量在你给它一个值之前是没有定义的。尝试在不为 printInstruction 提供值的情况下扩展 Compiler。如果给它一个非字符串值,如 42,这并不是真正的重新声明。
  • 我不明白,请多多包涵:),它似乎已定义,因为如果我给它赋值 42,编译器会写:覆盖 String 类型的 trait Compiler 中的变量 printInstruction;变量 printInstruction 的类型不兼容
  • 您的变量definition 中出现错误,因为超类中的变量declaration 具有不兼容的类型。我们声明了一个 String 类型的变量 printInstruction,我们将该值的值定义为例如“hi”。与java相反,您不能省略定义并获得默认值(null或0)。在这方面,'var x: String' 是抽象的,就像方法是抽象的一样;但是这个词没有被使用,它是未定义的。
  • 我认为我们彼此误解了很多,但我知道我只是粘贴它来告诉你编译器知道它是一个字符串,因此不是未定义的。感谢您的解释,尽管我已经开始了一个新线程,因为这对于 cmets 字段来说太长了。

标签: java oop scala inheritance traits


【解决方案1】:

对于 1:1 映射,应将 vars 更改为 defs。

trait Compiler {
  def printInstruction: String
}

class JavaCompiler extends Compiler {
  def printInstruction = "System.out.print(arg0);"
}

class ScalaCompiler extends Compiler {
  def printInstruction = "print(arg0);"
}

def 声明一个方法。当你不提供一个实现时,它就变成了一个抽象方法。

编辑:

这里使用的技术是一种有效且有用的技术。或者,您可以使用以下两种技术之一来模拟您的问题。

1) 歧视性工会。 (又名 sum 类型。)

请参阅this excellent article 了解此概念。以这种方式建模时,您的示例可能会如下所示:

sealed trait Compiler {
  def printInstruction: String = this match {
    case JavaCompiler => "System.out.print(arg0);"
    case ScalaCompiler => "print(arg0);"
  }
}

case object JavaCompiler extends Compiler
case object ScalaCompiler extends Compiler

2) 类型类模式。

Here 是 Daniel Sobral 关于这个主题的一篇很棒的帖子。您可以通过谷歌搜索术语类型类、模式、Scala、隐式等来挖掘更多信息。如果问题使用类型类模式建模,您的代码可能看起来像这样:

trait Compiler[C] {
  def printInstruction(c: C): String
}

case object JavaCompiler

implicit object JavaCompilerIsCompiler extends Compiler[JavaCompiler.type] {
  def printInstruction(c: JavaCompiler.type): String = "System.out.print(arg0);"
}

case object ScalaCompiler

implicit object ScalaCompilerIsCompiler extends Compiler[ScalaCompiler.type] {
  def printInstruction(c: ScalaCompiler.type) = "print(arg0);"
}

对于您的问题,原始方法和有区别的联合方法似乎是最好的建模解决方案。

【讨论】:

  • 或者至少到val而不是var
  • 感谢您的回答,但我不想要 1:1 映射我想要最好的 Scala 方法来解决我的“问题”。我正在尝试学习 Scala 的方式,而不仅仅是具有 Java 思维方式的 Scala 语法。
  • @Farmor,这里使用的技术在 Scala 中也被广泛使用。并非所有来自 Java 的技术都会因为在 Java 中使用而过时。
  • @Farmor,或者你可以使用有区别的联合。让我扩展我的答案。
【解决方案2】:

最惯用的方法是将def 用于抽象属性,将val 用于具体的只读属性。在统一访问原则下,val 可以用来实现一个方法:

trait Compiler {
  def printInstruction: String
}

class JavaCompiler extends Compiler {
  val printInstruction = "System.out.print(arg0);"
}

class ScalaCompiler extends Compiler {
  val printInstruction = "print(arg0);"
}

【讨论】:

    【解决方案3】:

    当我在 trait 中声明了变量后,为什么还要在类中重新声明一次?

    因为你声明了方法printInstruction的签名,但你没有说它做了什么。在class 中,因为它不是abstract class,所以应该定义所有函数。 顺便说一句,您可以直接在 trait Compiler 中定义 printInstruction,如果它应该在每个实现中都做同样的事情。

    【讨论】:

    • 也许我误解了 Scala 但 var 不是变量而不是方法?还是 Scala 将变量视为方法? printInstruction 不应该是一个方法,而是一个 String 字段,每个编译器都有不同的 String。
    • 我认为是你写了getPrintInstruction() 误导了我们,括号表明你写了一个方法(在java中它是一个方法)。所以变量不同于函数,因为你可以设置和获取变量,基本上你不能设置函数,你可以用它来“创建”结果。
    猜你喜欢
    • 1970-01-01
    • 2018-02-13
    • 1970-01-01
    • 2019-06-29
    • 1970-01-01
    • 2010-11-04
    • 1970-01-01
    • 2017-09-11
    • 2011-10-22
    相关资源
    最近更新 更多