2

不要被冗长的文字吓到,这些要点很简单,但需要一些代码来说明问题。:-)

设置:

假设我想创建一个特征,这里被建模为Converter某种类型的,它本身是通用的,但有一个类型化的方法convert(),它返回一个适当类型化的结果对象,比如 a Container[T]

 trait Converter {
   def convert[T]( input: T ) : Container[T]
 } 
 trait Container[T]  // details don't matter

我的问题是关于方法的类型约束,特别是对于强制平等,并且有两个密切相关的部分。

第 1 部分:现在说有一种特别适用于基于数组的内容的专用容器类型,如下所示:

 object Container {
   trait ForArrays[U] extends Container[Array[U]] 
 }

鉴于这种可能性,我现在想将 Converter 特别是convert()方法的返回类型专门化为专门的Container.ForArrays类型:

 object Converter {
   trait ForArrays extends Converter {
     // the following line is rubbish - how to do this right?
     def convert[E,T <: Array[E]]( input: T ) : Container.ForArrays[E]
   } 
 }

这样我就可以做这样的事情:

val converter = new Converter.ForArrays { ... }
val input = Array( 'A', 'B', 'C' )   
val converted : Container.ForArrays[Char] = converter.convert( input )

基本上我希望 Scala,如果已知转换器的类型是,也可以推断出asConverter.ForArrays的专门返回类型,即匹配的容器类型加上输入的数组类型。这是可能的吗?如果是这样,我该怎么做?例如,我如何在 convert() 上指定类型参数/边界(提供的只是一个替身——我不知道该怎么做)。哦,当然它仍然会覆盖它的超级方法,否则什么也得不到。convert[Char]()Container.ForArrays[Char]

第 2 部分:作为后备,如果这不可能,我当然可以将 convert 函数下推到以数组为中心的变体中,如下所示:

 trait Converter   // now pretty useless as a shared trait
 object Converter {
   trait ForValues extends Converter { 
     def convert[T]( input: T ) : Container[T] 
   }
   trait ForArrays extends Converter {
     def convert[E]( input: Array[E] ) : Container.ForArrays[E]
   } 
 }

好的。现在说我有一个更专业Converter.ForArrays.SetBased的,可以在内部使用一组 E 类型的元素(与“输入”数组元素类型相同)在转换期间执行一些特定的魔法。然而,该集合现在是 trait 的一个参数,如下所示:

 case class SetBased( set: Set[F] ) extends Converter.ForArrays {
   // the following line is also rubbish...
   def convert[E = F]( input: Array[E] ) : Container.ForArrays[E] = {...}
 }

同样,这是关于 convert() 方法的类型参数。这里的难点是:我如何将类的类型参数 - F- 与方法的类型参数 - E- 使 Scala 编译器只让用户调用convert()其元素与集合元素匹配的数组?例子:

val set = Set( 'X', 'Y', 'Z' )
val converter = new Converter.ForArrays.SetBased( set )
val input = Array( 'A', 'B', 'C' )   
val converted : Container.ForArrays[Char] = converter.convert( input )
4

2 回答 2

4

不,你不能。出于同样的原因,您不能在覆盖方法时缩小参数类型或扩大返回类型(但可以缩小返回类型)。但是,您可以执行以下操作(对于您的后备解决方案):

trait Converter {
  type Constraint[T]
} 

trait ForArrays extends Converter {
  def convert[E]( input: Array[E] )( implicit ev : Constraint[T] ) : Container.ForArrays[E]
}

case class SetBased[F](set: Set[F]) extends Converter {
   type Constraint[T] = T =:= F
   def convert[E]( input: Array[E] )( implicit ev : E =:= F ) = ...
} 
于 2011-10-25T10:39:55.553 回答
1

我将假设它Container.ForArrays是 的子类Container,没有这个,Converter.ForArrays.convert将与被覆盖的签名不匹配Converter.convert

尝试这样写:

object Converter {
  trait ForArrays extends Converter {
    def convert[E] (input: Array[E]): Container.ForArrays[E]
  } 
}

关于您的后备解决方案。如果两种类型相同,则只需使用相同的类型参数!

case class SetBased (set: Set[F]) extends Converter.ForArrays {
  def convert (input: Array[F]): Container.ForArrays[F] = {...}
}
于 2011-10-25T09:21:22.670 回答