浏览piece of Scala code at aws-scala by Atlassian时,您可以找到以下行:
type QueueURL = String @@ QueueURL.Marker我是Scala的新手,所以我可能错了,但是@@ (double at-sign)看起来不像是标准的内置Scala运算符。此外,细心的读者会发现它是从“scalaz”库中导入的:
import scalaz.{ Tag, @@ }@@是做什么的?为什么要用它呢?
正如评论中所提到的,actual definition is
type @@[A, T] = A这可能是一些提示。
发布于 2017-02-23 18:52:29
tag的想法是,通常你不想在任何地方使用原始的Long、Int等等--你想在代码中使用它们,但又不想在接口层传递它们:
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允许我们在类型上使用infix语法,所以我们也可以这样写:
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)的不同用法,并使用编译器检查他们是否犯了错误。
菊石中的示例:
@ type @@[A, T] = A with T
defined type @@
@ trait Username
defined trait Username
@ def passUsername(username: String @@ Username): Unit = ()
defined function passUsername
@ passUsername("test")
cmd3.sc:1: type mismatch;
String|String with Username
val res3 = passUsername("test")
^
Compilation Failed发布于 2017-02-22 23:59:53
标记使得创建新类型变得很容易。它使用@@符号将现有类型“标记”为另一个类型(换句话说,它创建了一个新类型)。因此,String @@ Text应该读作“带有文本标记的字符串”。不确定为什么要使用它。
https://stackoverflow.com/questions/42396382
复制相似问题