Scala泛型类型

时间:2015-08-31 09:59:34

标签: scala generics

我在那里,我正在尝试将 Command 责任链模式与Scala风格相结合。 基本上,我希望有一个Executor通过链传递命令并返回结果。 命令是返回T

的任何内容
class class Invoker {

  type Command[T] = () => T

  val handlers = new mutable.ListBuffer[PartialFunction[() => T, T]]

  def invoke[T](command: => T): Future[T] = Future {
    handlers.find(_.isDefinedAt(command)).map(_.apply(command))
  }

}

但是,因为我是scala初学者,所以handlers列表的泛型类型存在问题。我无法弄清楚如何在T的声明中定义handlers,以便invoke命令返回正确的类型(应该是T

有人可以帮我实现这种模式吗?

1 个答案:

答案 0 :(得分:2)

有几个粗略的地方,但我认为你最接近你想要的是(虽然,它不起作用,见下文):

import scala.collection.mutable
import scala.concurrent.Future

object Invoker {
  val handlers = new mutable.ListBuffer[PartialFunction[Any, Any]]

  def invoke[T](command: () => T): Future[T] = Future {
    handlers.collectFirst {
      case pf if pf.isDefinedAt(command) => pf(command)
    }.fold(throw new Exception("failure")) {
      _.asInstanceOf[T]
    }
  }
}

然而,

  1. 它不起作用,因为部分功能或更具体的模式匹配肯定不会像你期望的那样工作Function0

  2. 您通过删除丢失了大部分类型信息,并且必须依赖于您对部分功能的了解。

  3. 在scala中,调用asInstanceOf的需要是一个很好的指标,表明可以做得更好。

  4. @ 1 当您定义与Function0匹配的部分函数列表时,例如:

    val T1: () => Int = () => 1
    val T2: () => Int = () => 2
    val T3: () => Int = () => 3
    
    val pfs: Seq[PartialFunction[Any, Any]] = Seq(
      PartialFunction[Any, Any] {
        case T1 => T1()
      },
      PartialFunction[Any, Any] {
        case T2 => T2()
      },
      PartialFunction[Any, Any] {
        case T3 => T3()
      }
    )
    

    尝试查找任何函数文字的匹配项将导致MatchError:

    def invoke[T](c: () => T): T = {
      pfs.collectFirst {
        case pf if pf.isDefinedAt(c) => pf(c)
      }.fold(throw new Exception("failure")) {
        _.asInstanceOf[T]
      }
    }
    
    
    invoke(() => 1) |-> scala.MatchError: <function0> (of class abc.A$A290$A$A290$$anonfun$ti1$1)
    

    这只有在为允许的函数定义常量并且在调用invoke时才使用这些常量时才有效。

    您可以使用Invoker对象定义它们:

    object Invoker {
      val SomeCommand = () => 5 + 5
      val AnotherCommand = () => 5 * 5
    
    }
    

    但这完全可以消除任何灵活性。

    <强>最后:

    如果您希望能够执行任何 Command ,那么为什么还要保留处理程序列表?

    object Invoker {
      def invoke[T](command: () => T): Future[T] = Future {
        command()
      }
    }
    

    应该足够了。