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

时间:2017-02-22 15:58:22

标签: scala scalaz

浏览piece of Scala code at aws-scala by Atlassian时,您可以找到以下行:

type QueueURL = String @@ QueueURL.Marker

我是Scala的新手,所以我可能错了,但@@(双重符号)看起来并不像标准的内置Scala运算符。此外,一位敏锐的读者会发现它是从scalaz'库:

import scalaz.{ Tag, @@ }

@@做了什么?为什么要使用它?

如评论中所述,actual definition is

 type @@[A, T] = A

这可能是一些提示。

2 个答案:

答案 0 :(得分:4)

标记的想法是,你经常不想在任何地方使用原始的LongInt等等 - 好吧,你想在你的代码中使用它们,但是你不希望在接口级别传递它们:

def fetchUsers(numberOfUsers: Int, offset: Int): Seq[User]

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

override def fetchUsers(offset: Int, numberOfUsers: Int): Seq[User]

为避免您可以为两个参数使用不同的类型。一种方法是使用带有AnyVal的case类 - 如果你遵循一些规则,它会被编译器优化为原语。标签是为某些常见类型(可能不一定是基元)引入新类型的替代方法。 @@定义为

type @@[A, T] = A
你注意到了

因此,您可以将新类型定义为:

@@[String, QueueURL.Marker]

但是因为Scala允许我们在类型上使用中缀语法,所以我们也可以将它写成:

String @@ QueueURL.Marker

如果您使用例如依赖注入进行依赖注入,这将非常有用。 implicits或Macwire - 这些参数仅基于类型进行提取,因此每个可注入值具有不同的类型是必须的(在旁注Macwire实现它自己的@@版本 - 它们的方式略有不同,但它有同样的目的)。

然后你可以得到这样的代码:

def fetchUsers(numberOfUsers: Int @@ UsersNumber, offset: Int @@ Offset): Seq[User]

或:

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

def fetchUsers(numberOfUsers: UsersNumber, offset: UsersOffset): Seq[User]

我也看到了这个变种:

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

def fetchUsers(numberOfUsers: UsersNumber[Int], offset: UsersOffset[Int]): Seq[User]

查看aws-scala代码我假设他们想要实现第一个属性 - 能够区分一些常见类型的不同用法(如String)并使用编译器来检查它们是否没有错误。

答案 1 :(得分:0)

标记可以轻松创建新类型。它使用@@符号来标记"标记"现有类型作为另一种类型(换句话说,它创建一个新类型)。所以String @@ Text应该被读作" String用Text"标记。不知道为什么使用它。