我想在Scala中编写一个Multiset[T, S[_]]
类,它有两个类型参数:T
是元素的类型,而S
是集合的基础表示。
在此多集中,构造了S[(T, Int)]
的实例(在每对中,T
是元素,Int
是其出现次数)。
这在C ++中是可能的:
template<typename T, template<typename> S>
两个问题:
如何在S
上声明它必须是一个集合的约束? Multiset[T, S[_] <: Set[_]]
是否有效?
是否可以声明可以实例化S[(T, Int)]
实例的约束?这可以使用where S: new()
约束在C#中完成。
答案 0 :(得分:3)
第一个问题:请改用S[X] <: Set[X]
。使用下划线标记高阶类型参数是方便的,不需要用无用的名称来引起注意,但实际上你可以使用任何标识符。对于这种特殊情况,下划线不起作用。你甚至可以做S[X] <: Set[List[X]]
之类的事情。
第二个问题:没有直接的等价物,但我很少在C#中使用它,因为它暗示对象只能由无参数构造函数创建,这是一个很大的限制,对所有可能的用法都有效你的代码例如,您的类的用户可能希望在初始化时设置容量,或者使用池或其他任何东西。大多数时候,我在构造函数中需要Func<S>
委托,我可以添加一个静态工厂,接受new
作为方便,如
class Generic<T>
{
public Generic(..., Func<T> factory)
}
static class Generic
{
public Generic<T> Create(....) where T : new {
return new Generic(..., () => new T());
}
}
在scala中,您需要传递该函数。可能的替代方案是使用隐式参数,例如
trait Builder[A] {
def build(): A
}
object Builder {
def build[A: Builder] : A = implicitly[Builder[A]].build()
}
class Generic[A: Builder](....) {....
...
// instead of val a = new A()
val a = Builder.build[A]
....
}
然后,您可以确保构建器在参数类型的隐式作用域中可用,并且默认情况下将使用它。当默认值不是你想要的时候,你仍然可以明确地传递另一个。