多重集的高级类型
Higher-kinded types for multisets
我想在 Scala 中写一个 Multiset[T, S[_]]
class,它有两个类型参数:T
是元素的类型,而 S
是集合的底层表示。
在这个多重集中,构造了 S[(T, Int)]
的一个实例(在每一对中,T
是元素,Int
是它的出现次数)。
这在 C++ 中是可能的:
template<typename T, template<typename> S>
两个问题:
如何在S
上声明必须是集合的约束? Multiset[T, S[_] <: Set[_]]
有效吗?
是否可以声明S[(T, Int)]
的实例可以实例化的约束?这可以在 C# 中使用 where S: new()
约束来完成。
第一个问题:请改用S[X] <: Set[X]
。使用下划线标记高阶类型参数很方便,不需要用无用的名字来引起注意,但实际上你可以使用任何标识符。对于这种特殊情况,下划线不起作用。你甚至可以做 S[X] <: Set[List[X]]
这样的事情。
第二个问题:没有直接等价物,但是我很少在C#中使用它,因为它意味着对象只能由无参数构造函数创建,这是一个很大的限制,在强制所有可能使用您的代码。 class 的用户可能喜欢在初始化时设置容量,或者使用池等等。大多数时候,我在构造函数中需要一个 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]
....
}
那么您只需确保构建器在您的参数类型的隐式范围内可用,默认情况下将使用它。当默认的不是你想要的时,你仍然可以显式地传递另一个。
我想在 Scala 中写一个 Multiset[T, S[_]]
class,它有两个类型参数:T
是元素的类型,而 S
是集合的底层表示。
在这个多重集中,构造了 S[(T, Int)]
的一个实例(在每一对中,T
是元素,Int
是它的出现次数)。
这在 C++ 中是可能的:
template<typename T, template<typename> S>
两个问题:
如何在
S
上声明必须是集合的约束?Multiset[T, S[_] <: Set[_]]
有效吗?是否可以声明
S[(T, Int)]
的实例可以实例化的约束?这可以在 C# 中使用where S: new()
约束来完成。
第一个问题:请改用S[X] <: Set[X]
。使用下划线标记高阶类型参数很方便,不需要用无用的名字来引起注意,但实际上你可以使用任何标识符。对于这种特殊情况,下划线不起作用。你甚至可以做 S[X] <: Set[List[X]]
这样的事情。
第二个问题:没有直接等价物,但是我很少在C#中使用它,因为它意味着对象只能由无参数构造函数创建,这是一个很大的限制,在强制所有可能使用您的代码。 class 的用户可能喜欢在初始化时设置容量,或者使用池等等。大多数时候,我在构造函数中需要一个 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]
....
}
那么您只需确保构建器在您的参数类型的隐式范围内可用,默认情况下将使用它。当默认的不是你想要的时,你仍然可以显式地传递另一个。