1

我可以使用不带参数def的 a来实现:valdef

trait T { def foo: Int }
class C(val foo: Int) extends T

为什么这不能扩展到def将 N args 实现为 val FunctionN?我希望可以实现类似的东西:

def expensiveOperation(p: Int => Boolean) : List[Int]

带有懒惰的功能val。就像是:

val expensiveOperation = {
    val l = //get expensive list
    l.filter _ //partially applied function
}

我知道这种语法似乎不适用于 2.8。有什么我遗漏的东西,为什么我不能将参数作为函数来实现defval

4

4 回答 4

2

现在,后期编辑,我想我明白你在追求什么。但是你不能做你想做的,因为类型签名不匹配。

def x: Int = 5
val x: Int = 5

在这两种情况下,您什么都不提供并返回一个 Int(在本例中为 5)。伟大的!

def expensive(p: Int => Boolean): List[Int]

现在你提供一些东西。但是 val 只是某处的存储对象。您可以为标签所指的对象提供一些东西,但这与为标签“x”提供一些东西不同。

如果你想要一个 val 覆盖它,这是你需要使用的 def:

def expensive: (Int=>Boolean)=>List[Int]

现在你有了一个不带参数调用的东西,它返回的东西可以接受一个 Int=>Boolean 函数并给你一个 List[Int] 作为回报。这正是您使用 val 所得到的——在这两种情况下,您都拥有返回具有您想要的功能的对象的名称。

(在 Scala 中,vals 实际上被实现为带有 getter 方法的隐藏字段,这些方法不带参数并返回隐藏字段中的任何内容。所以它确实是一个类似于 def 的方法。)

于 2010-01-28T16:57:26.263 回答
2

Aval不接受参数,因为它被计算并存储在一个字段中。但我可能会向您推荐我过去两天在邮件列表中所做的大量帖子。

或者,更确切地说,让我们从 Java 的角度考虑它,因为 Scala 在 jvm 级别与 Java 兼容,它肯定必须遵守 jvm 规则。让我们从第一堂课开始:

abstract class X {
  def expensiveOperation(p: Int => Boolean) : List[Int] 
}

现在,让我们扩展它:

abstract class Y extends X {
  override val expensiveOperation: ((Int) => Boolean) => List[Int]
}

所以,从 Java 中,我们知道类X有方法expensiveOperation,它接收Function1[Int, Boolean]和返回List[Int]

现在我们去上课Y。自然,它必须定义相同的方法,但它还必须定义 getter expensiveOperation,它不接收任何参数并返回Function1[Function1[Int, Boolean],List[Int]]

只要不存在这种附加方法,它可能是可行的X。所以让我们定义它:

class Z extends Y {
  override val extensiveOperation = new Function1[Function1[Int, Boolean], List[Int]] {
    def apply(p: Int => Boolean) = List range (1, 10) filter p
  }
}

这是如何定义的?Scala 是否将apply的主体复制为expensiveOperation(接收参数的主体,而不是 getter 的主体)?它可能仍然可行。不过,让我们尝试其他方法:

class W(f: ((Int) => Boolean) => List[Int]) extends Y {
  override val extensiveOperation = f
}

现在,我们如何覆盖参数接收extensiveOperation?我想我们可以这样写:

override def extensiveOperation(p: Int => Boolean) = extensiveOperation.apply(p)

这是可行的。但我个人认为这有点令人费解。我的建议:写一个简短的 SID,并在 Scala 邮件列表上达成一致。但是,如果没有代码来实现它,我认为它被采用的机会不大——Scala 必须跟踪每个函数类型val来确定它是否覆盖了 a def

于 2010-01-28T19:48:10.893 回答
1

你总是可以把它转发给你的 val:

trait T {
  def expensiveOperation(p: Int => Boolean) : List[Int]
}

class C extends T {
  def expensiveOperation(p: Int => Boolean): List[Int] = {
      expensiveOperationVal(p) 
  }
  val expensiveOperationVal = { p: (Int=>Boolean) =>
    // ... lazy stuff
    List(1,2,3)
  }
}

而且,虽然这不能回答您的问题,但看起来除非您的// ... get expensive list代码依赖于 predicate p,否则您可以执行类似的操作:

class C extends T {
  def expensiveOperation(p: Int => Boolean): List[Int] = {
      myExpensiveList filter p 
  }
  lazy val myExpensiveList = {
    val l = // ... expensive stuff
    l
  }
}
于 2010-01-28T16:46:40.973 回答
0

编辑:好吧,我没有弄清楚你的真正意思。但如果你的意思是我的想法...

您可以使用缩写语法创建一个应用操作的 val:

val expensive = (p: (Int) => Boolean) => {
  val l = List(1,2,3,4)
  l filter p
}
scala> expensive(_<3)
res1: List[Int] = List(1,2)

但这实际上并没有缓存列表,这是我认为你想要的。原因是这种简写语法将 => 之后的所有内容都放入了 Function1 的 apply 方法中。您可能希望这样存储列表:

val expensive = new Function1[Int=>Boolean,List[Int]] {
  lazy val l = List(1,2,3,4)
  def apply(p: (Int) => Boolean) = { l filter p }
}

为此,我所知道的没有一个很好的速记法。

编辑:如果您乐于在该块之外创建列表,那么有一个速记(另见评论):

val expensive = List(1,2,3,4).filter _

scala> expensive(_ < 3)
res6: List[Int] = List(1, 2)
于 2010-01-28T15:11:20.117 回答