【问题标题】:Attempting to figure out the correct type for this试图找出正确的类型
【发布时间】:2020-04-15 11:50:09
【问题描述】:

抱歉,这将是一个有点菜鸟的问题。我有一个来自 slick 库的对象,其类型如下:

Query[(Rep[String], Rep[String]), (String, String), Seq]

我正在尝试编写一个接受查询作为参数的函数,尽管其中的序列长度不确定——也就是说,它也可以是:

Query[(Rep[String], Rep[String], Rep[String]), (String, String, String), Seq]

所以前两个组件包含三个元素而不是两个。我无法弄清楚这是如何完成的。我尝试了各种错误排列,例如Query[Product[Rep[String]], Product[String], Seq],但都无济于事,甚至我认为仅使用Any 的核选项也行不通。我的错误消息类似于

[error]  found   : Option[slick.driver.H2Driver.api.Query[(slick.driver.H2Driver.api.Rep[String], slick.driver.H2Driver.api.Rep[String]),(String, St
ring),Seq]]
[error]     (which expands to)  Option[slick.lifted.Query[(slick.lifted.Rep[String], slick.lifted.Rep[String]),(String, String),Seq]]
[error]  required: Option[slick.driver.H2Driver.api.Rep[scala.concurrent.Future[List[String]]]]
[error]     (which expands to)  Option[slick.lifted.Rep[scala.concurrent.Future[List[String]]]]
[error]       ReturnFunctions.completeQuery(db, query, serialize_and_send)

我认为我无法解决这个问题可能反映了对 scala、一般的强类型语言以及可能作为一个整体的计算缺乏一些基本的理解。在尝试将其传递给函数之前,我是否应该将此查询解析为更明确的形式?我还怀疑我没有正确解释原始类型 - 在这种情况下括号是什么意思?是不是 Query 期望接收三组参数,一个接一个,就像你做 fn(arg1)(arg2)(arg3) = ... 时一样?

感谢您对这个令人不安的困境的任何帮助。

【问题讨论】:

标签: scala slick typing


【解决方案1】:

我还怀疑我没有正确解释原始类型 - 在这种情况下括号是什么意思?

您已经看到了一个合理的高级领域,但让我们尝试提供帮助。

Query 类型始终具有三个类型参数。你会看到它们写成Query[M, U, C]

第一个参数M是一个元组。这就是括号在此上下文中的含义。

在您的第一个示例中,M 是两个元素的元组;第二个是三个。第二个参数U 也存在同样的情况。在Essential Slick 中有更多详细信息。

在 Scala 中,您可以使用泛型参数。这意味着你可以这样说:

def foo[M, U, C[_]](q: Query[M,U,C]) = ???

我们定义了一个方法:

  • 三种类型参数;和
  • 采用具有这些类型的查询的参数。

我们没有提到任何关于MUC 的内容(除了它是一个将类型作为参数的类型)。这意味着我们可以用它们做很多事情,但您可能不需要。

query enrichment in Slick 上的帖子给出了一个可能有用的更长(相关)示例。

正如 Dmytro 建议的那样,更好的方法是创建一个具体示例,说明您希望实现的目标并从那里开始工作。

【讨论】:

  • 谢谢你。我还注意到您回答了我最早提出的关于 slick MySQL 驱动程序的问题之一,因此我认为您与 slick 软件包本身的联系非常紧密——如果是这样,那么感谢您的工作,因为使用它真的很愉快。
【解决方案2】:

考虑Query类型构造函数的形状

Query[+E, U, C[_]]

我们说Query 是一个类型构造函数,因为它根据给定的类型参数EUC[_] 构造一个具体类型,类似于函数如何构造一个给定函数参数的具体值。

现在让我们尝试解构具体类型

Query[(Rep[String], Rep[String]), (String, String), Seq]

放入其构成类型参数。我们有

E     = (Rep[String], Rep[String])
U     = (String, String)
C[_]  = Seq

注意(A, B) 只是Tuple2[A, B] 的语法糖

E     = (Rep[String], Rep[String]) = Tuple2[Rep[String], Rep[String]]
U     = (String, String)           = Tuple2[String, String]
C[_]  = Seq                        = Seq

您可能想知道C[_] 中的下划线。这指定类型参数C 必须是类型构造函数,而不是具体类型。例如Seq 是类型构造函数,而Seq[Int] 不是。此外,您可能想知道+E 中的+。这指定了参数化类型的继承关系,或者换句话说,方差,例如,它指定Seq[Dog]是否是Seq[Animal]的子类型。

最后,让我们详细地编写生成的具体类型

Query[Tuple2[Rep[String], Rep[String]], Tuple2[String, String], Seq]

【讨论】:

  • 谢谢 - 这是一个清晰的解释。我需要对这些概念做一些进一步的阅读,但你给了我一些可以遵循的线索。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-06-28
  • 2022-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多