【问题标题】:Default function argument with generic types具有泛型类型的默认函数参数
【发布时间】:2018-02-18 15:12:55
【问题描述】:

我的函数获取另一个函数(将输入类型映射到输出类型)作为参数:

type Handled[S,R] = S => R

def myFunc[S,R](value: S, handled: Handled[S,R] = defaultHandled): R = {
  handled(value)
}

我需要编写 defaultHandled 函数来获取输入类型并按原样返回。

所以默认情况下,我想将输入类型映射到输出类型,其中输入类型与输出类型相同。对于任何输入类型,此函数应该简单地将输入传递给输出。 怎么做?

【问题讨论】:

    标签: scala generics default-value


    【解决方案1】:

    虽然在技术上这是可能的:

    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)
                           //            ^
    

    【讨论】:

      【解决方案2】:

      我想说,对于这种特定情况,有一个简单的解决方案可以完全达到您想要的结果:只需用重载替换默认参数。

      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
      

      【讨论】:

        【解决方案3】:

        如果SR 是两种任意类型(它们不相互依赖),那么我想这是不可能的(没有运行时转换)。您应该为每个SR 提供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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-06-20
          • 1970-01-01
          • 2010-10-04
          • 1970-01-01
          • 2016-11-14
          • 1970-01-01
          相关资源
          最近更新 更多