在scalaz中定义的@@运算符是什么?

Grz*_*zki 2 scala scalaz

Atlassian以aws-scala浏览一段Scala代码时,您会发现以下行:

type QueueURL = String @@ QueueURL.Marker
Run Code Online (Sandbox Code Playgroud)

我是Scala的新手,所以我可能错了,但是@@(双符号)似乎不是标准的内置Scala运算符。此外,细心的读者会发现它是从“ scalaz”库中导入的:

import scalaz.{ Tag, @@ }
Run Code Online (Sandbox Code Playgroud)

怎么@@办?为什么使用它?

如评论中所述,实际定义是

 type @@[A, T] = A
Run Code Online (Sandbox Code Playgroud)

这可能是一些提示。

Mat*_*zok 5

tag的想法是,您通常不想在任何地方使用raw LongInts等-好吧,您想在代码中使用它们,但又不想在接口级别传递它们:

def fetchUsers(numberOfUsers: Int, offset: Int): Seq[User]
Run Code Online (Sandbox Code Playgroud)

在这里,您必须使用命名参数,以确保您没有交换参数的顺序。另外,有人可能会犯错误以错误的顺序覆盖它:

override def fetchUsers(offset: Int, numberOfUsers: Int): Seq[User]
Run Code Online (Sandbox Code Playgroud)

为避免这种情况,您可以对两个参数使用不同的类型。做到这一点的一种方法是将case类与AnyVal- 一起使用-如果您遵循的规则很少,则编译器会将其优化为原语。标记是为某些常见类型(不一定是原语)引入新类型的替代方法。@@被定义为

type @@[A, T] = A
Run Code Online (Sandbox Code Playgroud)

如您所见。因此,您可以将新类型定义为:

@@[String, QueueURL.Marker]
Run Code Online (Sandbox Code Playgroud)

但是由于Scala允许我们对类型使用中缀语法,因此我们也可以将其编写为:

String @@ QueueURL.Marker
Run Code Online (Sandbox Code Playgroud)

如果您使用隐式或Macwire等进行依赖注入,这将特别有用-那里的参数仅基于类型进行提取,因此必须为每个可注入的值都具有可分辨的类型(在旁注中,Macwire实现了它自己的版本@@-这样做的方式略有不同,但目的相同)。

然后,您可以得到如下代码:

def fetchUsers(numberOfUsers: Int @@ UsersNumber, offset: Int @@ Offset): Seq[User]
Run Code Online (Sandbox Code Playgroud)

要么:

type UsersNumber = Int @@ UsersNumberTag
type UsersOffset = Int @@ UsersOffsetTag

def fetchUsers(numberOfUsers: UsersNumber, offset: UsersOffset): Seq[User]
Run Code Online (Sandbox Code Playgroud)

我也看到了这个变体:

type UsersNumber[T] = T @@ UsersNumberTag
type UsersOffset[T] = T @@ UsersOffsetTag

def fetchUsers(numberOfUsers: UsersNumber[Int], offset: UsersOffset[Int]): Seq[User]
Run Code Online (Sandbox Code Playgroud)

通过查看aws-scala代码,我认为他们想要实现第一个属性-能够区分某些常见类型(例如String)的不同用法,并使用编译器检查它们是否正确。