Scala,将运算符作为函数参数传递

11

我有这段代码:

for( i <- 0 to 8){
  ((numbers(i) - i)/3).abs + ((numbers(i) - i)%3).abs
}

我希望能够像标题所说的那样做一些类似这样的事情

for( i <- 0 to 8){
  by3(numbers(i), i, /) + by3(numbers(i), i, %)
}

def by3(a: Int, b: Int, op: Int => Int) = ((a - b) op 3).abs

也许还可以为此使用部分应用函数.. 但现在这可能实现了吗?如何做到?

3个回答

18

首先,需要将op正确定义为一个函数(具体来说是一个Function2)。

def operate(a: Int, b: Int, op: (Int, Int) => Int ) : Int = (op ((a - b), 3)).abs

在Scala中,操作符实际上是方法:+是Int(和Long、Double等)在Scala面向对象基础中的一种方法。然后,要将一个操作符(方法)作为函数传递,可以使用下划线符号进行提升:

operate(5, 3, _ + _)


12
为了消除下划线,您需要将函数定义为值。
val / = (a:Int, b: Int) => a / b
val % = (a:Int, b: Int) => a % b

def by3(a: Int, b: Int, fn: (Int, Int) => Int): Int = fn(a - b, 3).abs

(0 to 8).foreach(i => by3(numbers(i), i, /) + by3(numbers(i), i, %))

1
从语言灵活性的角度来看,这很酷,但从代码可维护性的角度来看,相当晦涩。我不会让它进入代码库。 - maasg

6

编辑/更新:

简明扼要地说,最短的方法是:

def doStuff(a: Int, b: Int, op: (Int, Int) => Int) = {op(a - b, 3).abs}

doStuff(4,1,_%_)

这样你就可以使用doStuff(numbers(i), i, _ / _) + doStuff(numbers(i), i, _ % _)


2
只有一件事 - 这真的很冗长。我正在寻找一个小函数,以避免为一个运算符重复大量字符,并且知道Scala,我几乎可以确定我可以在函数中传递%或/。这实际上是对我的问题的半回答,我正在寻找一种直接传递运算符的方法,而不是创建两个包装器函数。 - LowFieldTheory
哦,我已经编辑了答案,然后注意到@maasg已经发布了解决方案。对于造成的困扰,我很抱歉。 - tkroman
我想指出的是,尽管你的解决方案很好,但并不是我所要求的。或者至少,正如我所说,它只是解决方案的一半。我称其为“冗长”,不是因为解释,而是因为代码的长度。解释很好 :) - LowFieldTheory

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接