可以在Scala中编写类似于C ++模板的泛型返回类型吗?

时间:2010-11-17 03:17:47

标签: scala scala-2.8

在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 _

你能做到这一点,我只是错过了一些东西吗?或者如果没有,为什么不呢?

3 个答案:

答案 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