代码之家  ›  专栏  ›  技术社区  ›  wheaties

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

  •  5
  • wheaties  · 技术社区  · 14 年前

    在C++中,我可以做到以下几点:

    template<typename T, typename V>
    struct{
        void operator()(T _1, V _2){
            _2.foo( _1 );
        }
    };
    

    这让我可以任意决定使用任何对象,该对象有一个名为“foo”的方法,该方法接受某种类型的“T”,而不预先指定“foo”函数的参数类型或所述函数的返回类型。

    当我看斯卡拉的时候,会看到像 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”,为什么还要声明“foo”的返回类型?

    我希望能够

    def biff[T,V:{def foo( x:T ):Unit}] = //something
    

    def boff[T<:{def foo( x:Double ):_}]( y:T ) = y.foo _
    

    你能这样做吗?我只是错过了什么吗?如果不是,为什么不呢?

    3 回复  |  直到 14 年前
        1
  •  11
  •   Aaron Novstrup    14 年前

    更新:

    实际上,你可以做得更好 帮助您:

    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]
    }
    
        2
  •  6
  •   Daniel C. Sobral    14 年前

    斯卡拉和C++之间的根本区别是Scala中的每个类都被编译一次,然后就变成了可用的任何依赖于它的任何东西,而C++中的模板类必须为每一个新的依赖关系编译。

    所以,事实上,C++模板生成 N个 编译的类,而Scala只生成一个。

    它不能在编译时推断出实际的返回类型吗?

    因为它必须在编译类时决定,这可能与编译其使用时不同。

        3
  •  2
  •   Alexey Romanov    14 年前

    为了 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