2010-11-03 46 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