2012-01-27 11 views
1

私はScalaを学び始めています。私は単純なクロスコンパイラを行います。JavaインターフェイスをScalaに変換する正しい方法ですか?

私はプリントのような小さな指示をサポートします。

注:コードスニペットはテストまたはコンパイルされません。
ここで私は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);" 
} 
} 

は正しい"Scalaの道" 以下抜粋ですか?

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

EDIT:

私は新しいスレッドに私の2番目の質問を移動します。

+0

あなたはそれに価値を与えるまで、あなたが宣言された変数が定義されていません。 printInstructionの値を指定せずにCompilerを拡張しようとします。あなたが42のような文字列以外の値を与えても、それは本当に再宣言ではありません。 – thoredge

+0

私は分かりません。 :trait型の変数printInstructionをオーバーライドString型のコンパイラ。変数printInstructionに互換性のない型があります – Farmor

+0

スーパークラスの変数_declaration_に互換性のない型があるため、変数_definition_にエラーが発生します。 String型の変数printInstructionを宣言し、その値の値をたとえば "hi"と定義します。 javaとは異なり、定義を省略してデフォルト(nullまたは0)を取得することはできません。その点では、 'var x:String'はメソッドのように抽象メソッドです。その単語は使用されませんが、定義されていません。 – thoredge

答えて

2

1:1マッピングの場合、vardefに変更する必要があります。

trait Compiler { 
    def printInstruction: String 
} 

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

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

defが宣言されています。実装を提供しないと、抽象メソッドになります。

EDIT:

ここで使用される技術が有効かつ有用な技術です。また、次の2つの方法のいずれかを使用して問題をモデル化することもできます。

1)弁別された共用体。 (別名合計型)

この概念については、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による素晴らしい投稿です。あなたは、これはあなたのコードでは、型クラスのパターンでモデル化問題の場合のように見えるかもしれない方法である用語の型クラス、パターン、スカラ座、暗黙などをグーグルでいくつかのより多くを掘ることができます:あなたの問題のために

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);" 
} 

、元のアプローチと差別化された組合アプローチが最良のモデリングソリューションであるように見えます。

+0

あるいは、少なくとも「var」ではなく「val」です。 – Jesper

+0

答えをありがとうが、私は1対1のマッピングを望んでいません。私は "問題"を解決するために最高のScalaの方法を望んでいました。私は、Javaの考え方でScalaの構文だけでなく、Scalaの方法を学ぶことを試みています。 – Farmor

+0

@Farmor、ここで使われている技術はScalaでも広く使われています。 Javaの技術は、Javaで使用されているだけで廃止されるわけではありません。 – missingfaktor

0

なぜ私はその特性の中で宣言したときに、その変数をもう一度宣言しなければならないのですか?

メソッドprintInstructionの署名を宣言しましたが、それは何をしたのかわからなかったためです。 classでは、abstract classではないので、すべての機能を定義する必要があります。 ところで、printInstructiontrait Compilerに直接定義すると、すべての実装で同じことを行うはずです。

+0

私はScalaを誤解しているかもしれませんが、変数ではなくメソッドではありませんか?あるいは、Scalaは変数をメソッドとして扱いますか? printInstructionはメソッドではなく、各コンパイラごとに異なるStringを持つStringフィールドです。 – Farmor

+0

私は、あなたが 'getPrintInstruction()'を書いたことを誤解していると思います。括弧はメソッドを書きました(Javaではメソッドです)。あなたは変数を設定して取得することができるので、変数は関数とは異なります。基本的に関数を設定することはできません。その関数を使用して結果を「作成」することができます。 –

1

最も慣用的な方法は、抽象的なプロパティには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);" 
} 
関連する問題