在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)
这可能是一些提示。
tag的想法是,您通常不想在任何地方使用raw Long,Ints等-好吧,您想在代码中使用它们,但又不想在接口级别传递它们:
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)的不同用法,并使用编译器检查它们是否正确。
| 归档时间: |
|
| 查看次数: |
1078 次 |
| 最近记录: |