具有泛型类型的默认函数参数
Default function argument with generic types
我的函数获取另一个函数(将输入类型映射到输出类型)作为参数:
type Handled[S,R] = S => R
def myFunc[S,R](value: S, handled: Handled[S,R] = defaultHandled): R = {
handled(value)
}
我需要编写 defaultHandled 函数,它将获取输入类型并 return 按原样。
所以默认情况下我想将输入类型映射到输出类型,其中输入类型与输出类型相同。对于任何输入类型,此函数应该简单地将输入传递到输出。
怎么做?
如果 S
和 R
是两种任意类型(不相互依赖),那么我想这是不可能的(没有 运行-时间转换)。您应该为每个 S
、R
提供 defaultHandled
。 s => s
是 S => S
类型,而不是 S => R
任意 R
.
但是如果类型R
取决于类型 S
那么你可以考虑做以下事情:
trait Handled[S] {
type R
def apply(s: S): R
}
object Handled {
type Aux[S, R0] = Handled[S] {type R = R0}
def apply[S, R0](f: S => R0): Aux[S, R0] = new Handled[S] {
override type R = R0
override def apply(s: S): R = f(s)
}
}
def myFunc[S](value: S, handled: Handled[S] = Handled[S, S](s => s)): handled.R = {
handled(value)
}
这里Handled[S]
(与Handled.Aux[S, R]
相反)是一个existential type.
虽然从技术上讲这是可能的:
type Handled[S, R] = S => R
def defaultHandled[S, R](x: S): R = x.asInstanceOf[R]
def myFunc[S, R](value: S, handled: Handled[S, R] = defaultHandled[S, R] _): R = {
handled(value)
}
myFunc[Int, Int](1)
它不是类型安全的,通常不是一个好主意。例如,如果您尝试使用不同的类型参数调用 myFunc
,同时仍然依赖默认的 handled
值,您将得到运行时异常:
myFunc[Int, String](1)
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
Scala 解决这个问题的方法是将其作为隐式参数处理。在这种情况下,您可以提供编译器可能使用的默认实现。
type Handled[S, R] = S => R
implicit def defaultHandled[S]: Handled[S, S] = identity
def myFunc[S, R](value: S)(implicit handled: Handled[S, R]): R = {
handled(value)
}
myFunc(1) // compiles and works
myFunc[Int, String](1) // compilation error: Error:(11, 21) No implicit view
// available from Int => String.
//myFunc[Int, String](1)
// ^
我想说的是,对于这种特定情况,有一个简单的解决方案可以完全达到您想要的结果:只需将默认参数替换为重载即可。
type Handled[S,R] = S => R
def myFunc[S,R](value: S, handled: Handled[S,R]): R = {
handled(value)
}
def myFunc[S](value: S): S = value
我的函数获取另一个函数(将输入类型映射到输出类型)作为参数:
type Handled[S,R] = S => R
def myFunc[S,R](value: S, handled: Handled[S,R] = defaultHandled): R = {
handled(value)
}
我需要编写 defaultHandled 函数,它将获取输入类型并 return 按原样。
所以默认情况下我想将输入类型映射到输出类型,其中输入类型与输出类型相同。对于任何输入类型,此函数应该简单地将输入传递到输出。 怎么做?
如果 S
和 R
是两种任意类型(不相互依赖),那么我想这是不可能的(没有 运行-时间转换)。您应该为每个 S
、R
提供 defaultHandled
。 s => s
是 S => S
类型,而不是 S => R
任意 R
.
但是如果类型R
取决于类型 S
那么你可以考虑做以下事情:
trait Handled[S] {
type R
def apply(s: S): R
}
object Handled {
type Aux[S, R0] = Handled[S] {type R = R0}
def apply[S, R0](f: S => R0): Aux[S, R0] = new Handled[S] {
override type R = R0
override def apply(s: S): R = f(s)
}
}
def myFunc[S](value: S, handled: Handled[S] = Handled[S, S](s => s)): handled.R = {
handled(value)
}
这里Handled[S]
(与Handled.Aux[S, R]
相反)是一个existential type.
虽然从技术上讲这是可能的:
type Handled[S, R] = S => R
def defaultHandled[S, R](x: S): R = x.asInstanceOf[R]
def myFunc[S, R](value: S, handled: Handled[S, R] = defaultHandled[S, R] _): R = {
handled(value)
}
myFunc[Int, Int](1)
它不是类型安全的,通常不是一个好主意。例如,如果您尝试使用不同的类型参数调用 myFunc
,同时仍然依赖默认的 handled
值,您将得到运行时异常:
myFunc[Int, String](1)
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
Scala 解决这个问题的方法是将其作为隐式参数处理。在这种情况下,您可以提供编译器可能使用的默认实现。
type Handled[S, R] = S => R
implicit def defaultHandled[S]: Handled[S, S] = identity
def myFunc[S, R](value: S)(implicit handled: Handled[S, R]): R = {
handled(value)
}
myFunc(1) // compiles and works
myFunc[Int, String](1) // compilation error: Error:(11, 21) No implicit view
// available from Int => String.
//myFunc[Int, String](1)
// ^
我想说的是,对于这种特定情况,有一个简单的解决方案可以完全达到您想要的结果:只需将默认参数替换为重载即可。
type Handled[S,R] = S => R
def myFunc[S,R](value: S, handled: Handled[S,R]): R = {
handled(value)
}
def myFunc[S](value: S): S = value