2010-11-03 91 views
2

我不明白如何正確地在Scala中應用泛型類型。我設法實現了自己的控制結構(「除非」,「ForEach」),但它們目前僅限於「Int」類型......有誰知道如何更改適用於泛型類型的實現?Scala問題自定義控件結構<->類型參數

落實此事doesn't那麼多的我,但我真的想保持控制結構像現在這樣:

import Controls._ 

val Cond = false 
val Elements = List(1,2,3) 

Unless(Cond) { 
    var sum = 0 
    ForEach { 
    sum += Element 
    } In(Elements) 
    println("The Sum: " + sum) 
} 

我試了好幾個小時,但我不知道解決辦法用於類型參數的問題。 Here's我的 「內部」 的實施有限:

object Controls { 

    def Unless(cond: => Boolean)(block: => Unit) = { 
    if(!cond) block 
    } 

    var current = 0 
    def ForEach(block: => Unit) = { 
    new { 
     def In(list:List[Int]) = { 
     list foreach { i => 
      current = i 
      block 
     } 
     } 
    } 
    } 

    def Element = current 

} 

任何hint's是非常歡迎的我'真的卡住現在...

回答

4

基本上,要注入的Unless塊參數中的定義:

Unless 
(Cond) 
{ // you want Element available here 
    var sum = 0 
    ForEach { 
    sum += Element 
    } In(Elements) 
    println("The Sum: " + sum) 
} 

你不能外定義它,因爲它會提前修復類型。所以我會給你兩個解決方案。首先,注射的東西成塊的傳統方式是把它當作一個放慢參數:

Unless(Cond) { 
    var sum = 0 
    ForEach { Element => 
    sum += Element 
    } In(Elements) 
    println("The Sum: " + sum) 
} 

您將無法獲得單獨就像一個代碼,因爲沒有可用的編譯器來推斷Element的類型。因此,這兩種變化將需要:

ForEach[int] { Element => 
    ForEach { Element: Int => 

操作的代碼應該是這樣的:

object Controls { 
    def Unless(cond: => Boolean)(block: => Unit) = { 
    if(!cond) block 
    } 

    def ForEach[T](block: T => Unit) = { 
    new { 
     def In(list:List[T]) = { 
     list foreach block 
     } 
    } 
    } 
} 

另一個解決辦法是讓一個工廠特定類型的控件的,就像這樣:

object Controls { 
    def apply[T] = new Controls[T] 

    class Controls[T] { 
    def Unless(cond: => Boolean)(block: => Unit) = { 
     if(!cond) block 
    } 

    private var current: T = _ 
    def Element = current 
    def ForEach(block: => Unit) = { 
     new { 
     def In(list:List[T]) = { 
      list foreach { i => 
      current = i 
      block 
      } 
     } 
     } 
    } 
    } 
} 

然後你使用這樣的:

val controls = Controls[Int]; import controls._ 

其餘的工作就像在你的例子。

+0

我對您的解決方案有了一點打動 - 非常感謝Daniel!我不知道這樣一個事實,即編譯器可以像在「ForEach」的定義中那樣從塊參數推斷出一個類型參數。我需要找到關於類型推斷的詳細文檔... – 2010-11-04 10:17:57

+0

哦...現在我明白了! :) – 2010-11-04 10:32:44

1
def ForEach[T](block: => Unit): T = { 
    var current: T = _ 
    new { 
     def In(list: List[T]) = { 
      list foreach { i => 
       current = i 
       block 
      } 
     } 
    } 
    current 
} 

應該做的伎倆。

編輯:而且看到你在ForEach方法後使用current,你可能想要改變ForEach返回current。我編輯了代碼片段來反映這一點。

+0

我用你的方法取代了我的ForEach方法,但現在我得到:「局部變量必須被初始化」 - 我是新來的Scala,我從來沒有見過或者用這種方式用下劃線初始化:「var current :T = _「你能解釋它做了什麼以及它應該如何影響代碼? – 2010-11-03 18:42:52

+0

將其初始化爲'_'將其初始化爲其類型的默認值。 0代表整數,null代表對象引用等。 – 2010-11-03 18:51:29

+0

感謝你們的幫助,但我似乎錯過了這個問題。我想使用我的自定義控件結構_(!),因爲我現在使用它們(!)_(請參閱頁面上的第一個代碼段)。我想讓「ForEach」採取一個懶惰的代碼塊,然後用帶有集合的「In」方法返回一個對象。 ForEach塊中使用的Element方法應始終在遍歷中提供當前元素。這已經適用於基於「Int」的列表,但我希望它能在List中爲各種類型_工作。我希望我能澄清我的需求,再次感謝每一個案例! – 2010-11-03 19:02:21