在C ++中,我可以执行以下操作:
template<typename T, typename V>
struct{
void operator()(T _1, V _2){
_2.foo( _1 );
}
};
这让我可以随意决定使用任何一个有一些叫做“foo”的方法的对象,它取一些类型“T”,而不预先指定“foo”函数的参数类型和所述函数的返回类型。 / p>
当我查看Scala时,请看Function1之类的特征,并且正在使用像
这样的函数定义def foo[T<:{def foo():Unit}]( arg:T ) = //something
def bar( x:{def foo():Unit} ) = //something
def baz[T,V<:Function1[T,_]]( x:T, y:V ) = y( x )
我看着自己,想为什么我不能做同样的事情?为什么“baz”会返回Any?它不能在编译时推断出实际的返回类型吗?如果我甚至不使用它,为什么我必须声明返回类型“foo”?
我希望能够做到
def biff[T,V:{def foo( x:T ):Unit}] = //something
或
def boff[T<:{def foo( x:Double ):_}]( y:T ) = y.foo _
你能做到这一点,我只是错过了一些东西吗?或者如果没有,为什么不呢?
答案 0 :(得分:11)
更新:
实际上,你可以做得更好,类型推断器将帮助你:
def boff[T,R](y: T)(implicit e: T <:< {def foo(x: Double): R}) = e(y).foo _
对于baz
,相同的技术将改进类型推断:
def baz[T,R,V]( x:T, y:V )(implicit e: V <:< (T => R)) = e(y).apply( x )
scala> baz(1, (i: Int) => i+1)
res0: Int = 2
你可以通过以下方式做得更好:
def baz[T,R](x: T)(f: T => R) = f(x)
第一个解决方案:
类型推断器不会为您提供T
类型,但您可以这样做:
class Boff[T] {
def apply[R](y: T)(implicit e: T <:< {def foo(x: Double): R}) = e(y).foo _
}
object boff {
def apply[T] = new Boff[T]
}
答案 1 :(得分:6)
Scala和C ++之间的根本区别在于Scala中的每个类都编译一次,然后按原样可用于依赖于它的任何东西,而C ++中的模板化类必须为每个新依赖项编译。
因此,实际上,C ++模板会生成 N 编译的类,而Scala只生成一个。
它不能在编译时推断出实际的返回类型吗?
因为必须在编译类时决定它,这可能与编译它的时间不同。
答案 2 :(得分:2)
foo
:
def foo[R,T<:{def foo():R}]( arg:T ) = ...
如果是baz
,您说V
必须是从T
到某种类型的函数。此类型不能出现在结果类型中:您怎么写它?因此编译器只能推断出结果类型为Any
。但是,如果你给它一个名字,你就得到了
scala> def baz[T,R,V<:Function1[T,R]]( x:T, y:V ) = y( x )
baz: [T,R,V <: (T) => R](x: T,y: V)R