我真的很想知道差异在哪里,更一般地说,找出不能使用HLists的规范用例(或者说,不会比常规列表产生任何好处).
(我知道TupleNScala 中有22个(我相信),而一个只需要一个HList,但这不是我感兴趣的那种概念差异.)
我在下面的文字中标出了几个问题.它实际上可能没有必要回答它们,它们更倾向于指出我不清楚的事情,并指导某些方向的讨论.
我最近在SO上看到了几个人们建议使用HLists的答案(例如,由Shapeless提供),包括对这个问题的删除答案.它引发了这一讨论,从而引发了这个问题.
在我看来,只有当您静态地知道元素的数量及其精确类型时,才会使用hlists.这个数字实际上并不重要,但你似乎不太可能需要生成一个包含不同但静态精确已知类型的元素的列表,但是你不能静态地知道它们的数量.问题1:你甚至可以写一个这样的例子,例如,在循环中吗?我的直觉是,拥有静态精确的hlist与静态未知数量的任意元素(相对于给定的类层次结构的任意)只是不兼容.
如果这是真的,即你静态地知道数字和类型 - 问题2:为什么不使用n元组?当然,你可以类型安全地映射和折叠一个HList(你也可以,但不是类型安全地,借助于一个元组productIterator),但由于元素的数量和类型是静态已知的,你可能只是访问元组元素直接执行操作.
另一方面,如果f您在hlist上映射的函数是如此通用以至于它接受所有元素 - 问题3:为什么不通过它使用它productIterator.map?好的,一个有趣的区别可能来自方法重载:如果我们有几个重载f的,拥有hlist提供的更强的类型信息(与productIterator相反)可以允许编译器选择更具体的f.但是,我不确定这在Scala中是否真的有用,因为方法和功能不一样.
基于相同的假设,即您需要静态地知道元素的数量和类型 - 问题4:可以在元素依赖于任何类型的用户交互的情况下使用hlists吗?例如,想象用循环内的元素填充hlist; 从某个地方(UI,配置文件,演员交互,网络)读取元素,直到某个条件成立.什么类型的hlist是什么?类似于接口规范getElements:HList [...]应该使用静态未知长度的列表,并允许系统中的组件A从组件B获得这样的任意元素列表.
在某些用例中,创建对象的副本很有用,该对象是一组案例类的案例类的实例,它们具有共同的特定值.
例如,让我们考虑以下案例类:
case class Foo(id: Option[Int])
case class Bar(arg0: String, id: Option[Int])
case class Baz(arg0: Int, id: Option[Int], arg2: String)
Run Code Online (Sandbox Code Playgroud)
然后copy可以在每个案例类实例上调用:
val newId = Some(1)
Foo(None).copy(id = newId)
Bar("bar", None).copy(id = newId)
Baz(42, None, "baz").copy(id = newId)
Run Code Online (Sandbox Code Playgroud)
type Copyable[T] = { def copy(id: Option[Int]): T }
// THIS DOES *NOT* WORK FOR CASE CLASSES
def withId[T <: Copyable[T]](obj: T, newId: Option[Int]): T =
obj.copy(id = newId)
Run Code Online (Sandbox Code Playgroud)
所以我创建了一个scala宏,它完成了这项工作(几乎):
import scala.reflect.macros.Context
object Entity {
import …Run Code Online (Sandbox Code Playgroud) 我正在尝试这样做:
trait IdentifiableModel[T] {
self: { def copy(id: ObjectId): T } =>
val id: ObjectId
}
Run Code Online (Sandbox Code Playgroud)
我发现其他一些相关的问题试图做类似的事情,但他们并没有真正回答这个问题.在我的例子中,我正在尝试复制所有共享id值的IdentifiableModel的case类子类
让我们假设我们有一个共同的特质模型.
trait Model {
def id: String
def updated: Date
}
Run Code Online (Sandbox Code Playgroud)
我们有2个案例类来扩展这个特性.
case class C1(id: String, updated: Date, foo: String) extends Model
case class C2(id: String, updated: Date, bar: Int) extends Model
Run Code Online (Sandbox Code Playgroud)
是否可以编写如下所示的实用程序函数,该函数将Model作为参数并返回带有更新字段的更新值的副本?
object Model {
def update[T <: Model](model: T): T = {
model.copy(updated = new Date) // This code does not compile.
}
}
Run Code Online (Sandbox Code Playgroud) 我有以下情况/代码;
trait Model {
def myField: String
}
case class MyModel(myField: String) extends Model
Run Code Online (Sandbox Code Playgroud)
在为我的模型类创建DAO的传统模型中,我想创建一个包含一些通用CRUD操作的DAO特征.注意......持久性框架在这里并不重要......问题是在使用泛型的特征中使用案例类方法.
据说我想创造以下特质;
trait DAO[M <: Model] {
def insert(model: M): M = {
... do work
m.copy(myField="someval")
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,代码不会编译,因为泛型M对"案例类"一无所知.如果这里有一些简单的解决方案,可以将泛型声明为需要成为一种案例吗?或者Model trait是否应该声明一个任何扩展类必须实现的复制方法,并且它是一个case类吗?