2012-01-27 97 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);" 
} 
} 

低於正確「斯卡拉方式」 的片段?

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

編輯:

我將我的第二個問題轉移到一個新的線程。

+0

你聲明沒有定義,直到你給它一個值的變量。嘗試擴展編譯器而不給printIntru提供一個值。它不是一個真正的重新聲明,因爲你可以看到,如果你給它一個非字符串值如42。 – thoredge 2012-01-27 12:47:57

+0

我不明白,請忍受我:),它似乎定義,因爲如果我給它的值42編譯器寫:在trait類型爲String的Compiler中重寫變量printInstruction;變量printInstruction具有不兼容的類型 – Farmor 2012-01-27 13:37:10

+0

您的變量_definition_中出現錯誤,因爲超類中的變量_declaration_具有不兼容的類型。我們聲明瞭一個String類型的變量printInstruction,並且我們將該值的值定義爲例如「hi」。與java相反,您不能忽略定義並獲得默認值(null或0)。在這方面,'var x:String'是抽象的,就像一個方法是抽象的;然而這個詞沒有被使用,它是未定義的。 – thoredge 2012-01-27 13:52:03

回答

2

對於1:1映射,應將那些var s更改爲def s。

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)歧視的工會。 (又名總和類型)

請參閱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)Type class pattern。

Here是Daniel Sobral在這個話題上的一篇很棒的文章。您可以通過谷歌搜索挖出更多的一些條款類型類,模式,斯卡拉,implicits等,這是你的代碼的外觀一樣,如果這個問題與類型的類模式爲藍本:

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

或者至少到'val'而不是'var'。 – Jesper 2012-01-27 12:36:31

+0

感謝您的答案,但我不想要1:1映射我想要最好的Scala方式來解決我的「問題」。我正在嘗試學習Scala方法,而不是隻使用Java思維的Scala語法。 – Farmor 2012-01-27 12:40:12

+0

@Farmor,這裏使用的技術也在Scala中廣泛使用。並非所有來自Java的技術都會因Java中的使用而過時。 – missingfaktor 2012-01-27 12:47:34

0

爲什麼我必須在課堂上再次聲明變量一次?

因爲您宣佈了方法printInstruction的簽名,但您沒有說明它做了什麼。在class中,因爲它不是abstract class所以應該定義所有功能。 順便說一下,如果應該在每個實現中執行相同的操作,則可以直接在trait Compiler中定義printInstruction

+0

也許我誤解了Scala,但不是變量而不是方法?或者Scala將變量當作方法處理?對於每個編譯器,printInstruction不應該是一個方法,而應該是一個字符串字段,其中字符串不同。 – Farmor 2012-01-27 12:43:50

+0

我認爲你寫了'getPrintInstruction()'是誤導了我們,括號是你寫了一個方法的標誌(在java中它是一個方法)。因此,變量與函數不同,因爲您可以設置和獲取變量,基本上不能設置函數,您可以使用它來「創建」結果。 – 2012-01-27 12:47:51

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);" 
} 
相關問題