我是Scala的新手,能够将函数传递给其他函数非常简洁 - 但是我可以将任意函数引用传递给另一个函数吗?所述功能参数的arity将是固定的(也就是说,我也很好奇你是否可以传递任意arity的函数)。我不断遇到类型错误。我尝试过使用Any
,但似乎没有帮助。
例如,我有以下代码:
class CodeRunner(val user_defined: (Int) => Unit) {
def run(input: Int) = {
user_defined(input)
}
}
def arbitrary_code(input: Int) = { println("Running with input " + input) }
val d1 = new CodeRunner(arbitrary_code)
d1.run(4)
我得到了:
Running with input 4
现在,让我们说我想传递以下函数:
def arbitrary_code(input: String) = { println("Running with input " + input) }
如何更改我的CodeRunner
课程以处理它们?
答案 0 :(得分:9)
如何更改我的
CodeRunner
课程以处理它们?
您可以将任意类型设为类的参数:
class CodeRunner[T](val user_defined: (T) => Unit) {
def run(input: T) = {
user_defined(input)
}
}
def arbitrary_code(input: Int) = { println("Running with input " + input) }
val d1 = new CodeRunner(arbitrary_code)
d1.run(4)
def arbitrary_code2(input: String) = { println("Running with input " + input) }
val d2 = new CodeRunner(arbitrary_code2)
d2.run("hello")
请注意,d2
的类型为CodeRunner[String]
,d1
无法分配给CodeRunner[Int]
。
答案 1 :(得分:3)
通用类型允许您定义具有占位符类型的类,该类在实例化对象时指定。编译器很高兴,因为它可以确保一切都是类型安全的,并且您很高兴,因为您可以实例化对象并为值传递任意类型。
要在类中使用泛型类型,可以像这样修改它:
class CodeRunner[T] (val user_defined: (T) => Unit) {
def run(input: T) = {
user_defined(input)
}
}
“类CodeRunner”之后的[T]是重要的部分 - 它定义了一个泛型类型T(你可以用另一个大写字母替换T等),它将在类定义中使用。 / p>
所以,如果你定义一个方法:
def arbitrary_code(input: String) = { println("Running with input " + input) }
然后将其传递给:
val d1 = new CodeRunner(arbitrary_code)
...然后编译器说“aha,对于CodeRunner的这个实例,泛型类型T是一个字符串”。如果你调用
d1.run("string")
编译器会很高兴,但不会让你传入d1.run(4)。
答案 2 :(得分:2)
要传递任意函数,您当然可以使用泛型:
def run[T,U](f: T => U) = println(f)
对于任意arity,这是不可能的,因为类型T =>的函数。 U是Function1 [U,T]的实例,类型(T,U)的函数=> V是Function2 [T,U,V]的实例。 (另外,我找不到任何有用的用例)。 然而,有一个称为“currying”的聪明概念。它包含转换一个带有多个参数的函数,并在一个函数中返回一个值,该函数接受一个参数并返回另一个函数。 这是一个例子:
def nonCurriedAdd(x: Int, y: Int) = x + y
// nonCurriedAdd(4,6)
def curriedAdd(x: Int) = (y: Int) => x + y
// we can use some syntax sugar
def curriedAdd(x: Int)(y: Int) = x + y
// curriedAdd(4)(6)
所以,你现在可以做`d1.run(curriedAdd)。 您还可以使用“curried”方法转换curried函数中的非curried函数:
d1.run(nonCurriedAdd.curried)
答案 3 :(得分:1)
我可以将任意函数引用传递给另一个函数吗?所述功能参数的arity将是固定的
与往常一样,记下您正在开发的功能的类型,一切都变得清晰。
你的单词“任意”表示函数参数适用于任何类型。也就是说,它们是多态函数(或某些语言中的通用函数)。
以下内容应该相当干净地转换为Scala:
== The type of an "arbitrary" function of fixed arity
f :: a -> b -> c -> d
-- The type of a function that accepts such a
-- function as an argument, and does something with it:
g :: (a -> b -> c -> d) -> a -> b -> c -> d
-- And a function that implements something of that type
g f a b c = f a b c
你可能能够提出一些其他的高阶函数,它们采用固定的arity函数,但是任意(即多态)类型,并对它们进行操作。
经典的高阶函数是例如
map :: (a -> b) -> [a] -> [b]
fold :: (a -> b -> b) -> b -> [a] -> b
还有很多人。
答案 4 :(得分:0)
scala> object codeRunner {
| def run[InputType, OutputType](code: InputType => OutputType) = (input: InputType) => code(input)
| }
defined module codeRunner
scala> def someCode(x: Int) {
| println("This code uses " + x)
| }
someCode: (x: Int)Unit
scala> def otherCode(y: String) {
| println("This code uses " + y)
| }
otherCode: (y: String)Unit
scala> codeRunner.run(someCode)(10)
This code uses 10
scala> codeRunner.run(otherCode)("hello")
This code uses "hello"