From 6b8409d782f588cff71ccaf529eafae3adb6a849 Mon Sep 17 00:00:00 2001 From: liguobin Date: Thu, 24 Sep 2020 18:55:38 +0800 Subject: [PATCH 1/5] add reflect tags --- _overviews/reflection/thread-safety.md | 2 +- _overviews/reflection/typetags-manifests.md | 2 +- _zh-cn/overviews/reflection/thread-safety.md | 49 +++++++ .../reflection/typetags-manifests.md | 134 ++++++++++++++++++ 4 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 _zh-cn/overviews/reflection/thread-safety.md create mode 100644 _zh-cn/overviews/reflection/typetags-manifests.md diff --git a/_overviews/reflection/thread-safety.md b/_overviews/reflection/thread-safety.md index 5ea8071637..862d465872 100644 --- a/_overviews/reflection/thread-safety.md +++ b/_overviews/reflection/thread-safety.md @@ -6,7 +6,7 @@ overview-name: Reflection num: 6 -languages: [ja] +languages: [ja, zh-cn] permalink: /overviews/reflection/:title.html --- diff --git a/_overviews/reflection/typetags-manifests.md b/_overviews/reflection/typetags-manifests.md index e1c32a1c8f..6b6febff89 100644 --- a/_overviews/reflection/typetags-manifests.md +++ b/_overviews/reflection/typetags-manifests.md @@ -6,7 +6,7 @@ overview-name: Reflection num: 5 -languages: [ja] +languages: [ja, zh-cn] permalink: /overviews/reflection/:title.html --- diff --git a/_zh-cn/overviews/reflection/thread-safety.md b/_zh-cn/overviews/reflection/thread-safety.md new file mode 100644 index 0000000000..d191848766 --- /dev/null +++ b/_zh-cn/overviews/reflection/thread-safety.md @@ -0,0 +1,49 @@ +--- +layout: multipage-overview +title: 线程安全 +partof: reflection +overview-name: Reflection + +num: 6 + +language: zh-cn +permalink: /zh-cn/overviews/reflection/:title.html +--- + +EXPERIMENTAL + +**Eugene Burmako** + +遗憾的是,在scala2.10.0发布的现行状态下,反射不是线程安全的。 +这里有个JIRA问题 [SI-6240](https://issues.scala-lang.org/browse/SI-6240),它可以用来跟踪我们的进度和查找技术细节,下面是最新技术的简要总结。 + +

NEWThread safety issues have been fixed in Scala 2.11.0-RC1, but we are going to keep this document available for now, since the problem still remains in the Scala 2.10.x series, and we currently don't have concrete plans on when the fix is going to be backported.

+ +目前,在反射相关方面存在两种竞争状态。 第一是反射的初始化(当调用代码首次访问`scala.reflect.runtime.universe`时)无法从多个线程安全地调用。第二是符号的初始化(当调用代码第一次访问符号的标记或类型签名时)也不安全。 +这是一个典型的表现: + + java.lang.NullPointerException: + at s.r.i.Types$TypeRef.computeHashCode(Types.scala:2332) + at s.r.i.Types$UniqueType.(Types.scala:1274) + at s.r.i.Types$TypeRef.(Types.scala:2315) + at s.r.i.Types$NoArgsTypeRef.(Types.scala:2107) + at s.r.i.Types$ModuleTypeRef.(Types.scala:2078) + at s.r.i.Types$PackageTypeRef.(Types.scala:2095) + at s.r.i.Types$TypeRef$.apply(Types.scala:2516) + at s.r.i.Types$class.typeRef(Types.scala:3577) + at s.r.i.SymbolTable.typeRef(SymbolTable.scala:13) + at s.r.i.Symbols$TypeSymbol.newTypeRef(Symbols.scala:2754) + +好消息是,编译时反射(通过`scala.reflect.macros.Context`暴露给宏的那一种)比运行时反射(通过`scala.reflect.runtime.universe`暴露出的那一种)更不容易受到线程问题的影响。 +第一个原因是,当宏有机会运行时,编译时反射`universe`已经初始化,这规避了我们的竞争条件1。第二个理由是至今为止没有编译程序本身就是线程安全,所以没有并行执行的工具。但是,如果您的宏产生了多个线程,则你仍应该小心。 + + +不过,对于运行时反射来说,情况要糟糕得多。首次初始化`scala.reflect.runtime.universe`时,称为反射初始化,而且这种初始化可以间接发生。 +此处最突出的示例是,调用带有`TypeTag`上下文边界的方法可能会带来问题,因为调用这种方法,Scala通常需要构造一个自动生成的类型标签,该标签需要创建一个类型,并需要初始化反射`universe`。 +这个结果是,如果不采取特殊措施,就无法在测试中可靠地调用基于`TypeTag`的方法,这是因为sbt等很多工具并行执行测试。 + +汇总: +* 如果您正在编写一个没有显式创建线程的宏那就没有问题。 +* 线程或参与者(actors)混在一起的运行时反射可能很危险。 +* 多个带有`TypeTag`上下文边界的线程调用方法可能导致不确定的结果。 +* 请查看 [SI-6240](https://issues.scala-lang.org/browse/SI-6240),以了解我们在此问题上的进展。 \ No newline at end of file diff --git a/_zh-cn/overviews/reflection/typetags-manifests.md b/_zh-cn/overviews/reflection/typetags-manifests.md new file mode 100644 index 0000000000..5434ad6fab --- /dev/null +++ b/_zh-cn/overviews/reflection/typetags-manifests.md @@ -0,0 +1,134 @@ +--- +layout: multipage-overview +title: TypeTags and Manifests +partof: reflection +overview-name: Reflection + +num: 5 + +languages: [ja, zh-cn] +permalink: /overviews/reflection/:title.html +--- + +与其他JVM语言一样,Scala的类型在运行时被擦除。这意味着,如果要检查某个实例的运行时类型,则可能无法访问Scala编译器在编译时可用的所有类型信息。 + +如`scala.reflect.Manifest`,`TypeTags`可以看作是将编译时可用的所有类型信息携带到运行时的对象。 +例如,`TypeTag[T]`封装了某个编译时类型`T`的运行时类型表示。但是请注意,`TypeTag`应该被认为是对2.10之前的`Manifest`概念的更丰富的替代品,后者还与Scala反射完全集成。 + +有三种不同类型的类型标记: + +1. `scala.reflect.api.TypeTags#TypeTag`。 +Scala类型的完整类型描述符。例如,`TypeTag[List[String]]`包含所有类型信息,在本例中是类型`scala.List[String]`。 + +2. `scala.reflect.ClassTag`。 +Scala类型的部分类型描述符。例如,`ClassTag[List[String]]`只包含已删除的类类型信息,在本例中为`scala.collection.immutable.List`。`ClassTag`只提供对类型的运行时类的访问。类似于`scala.reflect.ClassManifest`。 + +3. `scala.reflect.api.TypeTags#WeakTypeTag`. +抽象类型的类型描述符(参见下面相应的小节)。 + +## 获取`TypeTag` + +与`Manifest`类似,`TypeTag`总是由编译器生成,可以通过三种方式获得。 + +### 通过方法`typeTag`、`classTag`或`weakTypeTag` + +通过使用通过`Universe`提供的方法`typeTag`,就可以直接获得特定类型的`TypeTag`。 + +例如,要获取表示`Int`的`TypeTag`,我们可以执行以下操作: + + import scala.reflect.runtime.universe._ + val tt = typeTag[Int] + +或者类似地,要获得表示`String`的`ClassTag`,我们可以执行以下操作: + + import scala.reflect._ + val ct = classTag[String] + +这些方法中的每个方法都为给定的类型参数`T`构造一个`TypeTag[T]`或`ClassTag[T]`。 + +### 使用类型为`TypeTag[T]`、`ClassTag[T]`或`WeakTypeTag[T]`的隐式参数 + +与`Manifest`一样,实际上可以 _请求_ 编译器生成`TypeTag`。这只需指定一个类型为`TypeTag[T]`的隐式 _票据_ 参数即可完成。如果编译器在隐式搜索期间找不到匹配的隐式值,它将自动生成一个`TypeTag[T]`。 + +_注意_:这通常是通过在方法上使用隐式参数来实现的,并且只能在类上。 + +例如,我们可以编写一个方法,它可以接受任意对象,并且使用`TypeTag`打印有关该对象的类型参数的信息: + + import scala.reflect.runtime.universe._ + + def paramInfo[T](x: T)(implicit tag: TypeTag[T]): Unit = { + val targs = tag.tpe match { case TypeRef(_, _, args) => args } + println(s"type of $x has type arguments $targs") + } + +这里,我们在`T`上编写了一个参数化的泛型方法`paramInfo`,并提供了一个隐式参数`(implicit tag: TypeTag[T])`。 +那我们就可以使用`TypeTag`的方法`tpe`直接访问`tag`表示的类型(`type`类型)。 + +然后,我们可以使用方法`paramInfo`,如下所示: + + scala> paramInfo(42) + type of 42 has type arguments List() + + scala> paramInfo(List(1, 2)) + type of List(1, 2) has type arguments List(Int) + +### 使用类型参数的上下文绑定 + +要实现与上述完全相同的效果,一种不太冗长的方法是在类型参数上使用上下文绑定。不需要提供单独的隐式参数,只需在类型参数列表中包含`TypeTag`,如下所示: + + def myMethod[T: TypeTag] = ... + +给定上下文绑定的`[T: TypeTag]`,编译器只需生成类型为`TypeTag[T]`的隐式参数,这将重写方法以进行查找,就像上一节中使用隐式参数的示例一样。 + +上面重写为使用上下文边界的示例如下: + + + import scala.reflect.runtime.universe._ + + def paramInfo[T: TypeTag](x: T): Unit = { + val targs = typeOf[T] match { case TypeRef(_, _, args) => args } + println(s"type of $x has type arguments $targs") + } + + scala> paramInfo(42) + type of 42 has type arguments List() + + scala> paramInfo(List(1, 2)) + type of List(1, 2) has type arguments List(Int) + +## WeakTypeTags + +`WeakTypeTag[T]`泛化了`TypeTag`(意思是`TypeTag`是继承自`WeakTypeTag`的),`WeakTypeTag`与普通的`TypeTag`不同, + +其类型表示的组件可以是对类型参数或抽象类型的引用。但是,`WeakTypeTag[T]`试图尽可能的具体(意思是如果都存在则优先更加具体的类型(参数)),也就是说,如果类型标记可用于被引用的类型参数或抽象类型,则它们用于将具体类型嵌入到`WeakTypeTag[T]`中。 + +继续上面的例子: + + def weakParamInfo[T](x: T)(implicit tag: WeakTypeTag[T]): Unit = { + val targs = tag.tpe match { case TypeRef(_, _, args) => args } + println(s"type of $x has type arguments $targs") + } + + scala> def foo[T] = weakParamInfo(List[T]()) + foo: [T]=> Unit + + scala> foo[Int] + type of List() has type arguments List(T) + +## TypeTags and Manifests + +`TypeTag`可以大致对应2.10之前的`scala.reflect.Manifest`、 虽然`scala.reflect.ClassTag`对应于`scala.reflect.ClassManifest`而`scala.reflect.api.TypeTags#TypeTag`主要对应于`scala.reflect.Manifest`,但其他2.10版之前的`Manifest`类型与2.10版的`Tag`类型没有直接对应关系。 + +- **不支持scala.reflect.OptManifest。** +这是因为`Tag`可以具体化任意类型,所以它们总是可用的。 + +- **没有对应的scala.reflect.AnyValManifest。** +取而代之的是,可以将其`Tag`与基本`Tag`之一(在相应的伴随对象中定义)进行比较,以找出其是否代表原始值类。此外,可以简单地使用`.tpe.typeSymbol.isPrimitiveValueClass`。 + +- **无法替换Manifest伴随对象中定义的工厂方法。** +取而代之的是,可以使用Java(用于类)和Scala(用于类型)提供的反射API生成相应的类型。 + +- **不支持某些manifest操作(即`<:<`, `>:>`和`typeArguments`)。** +取而代之的是,可以使用Java(用于类)和Scala(用于类型)提供的反射API。 + +在Scala 2.10中,不建议使用`scala.reflect.ClassManifest`,而推荐使用`TypeTag`和`ClassTag`,并且计划在即将发布的版本中弃用`scala.reflect.Manifest`。因此,建议迁移任何基于`Manifest`的API以使用`Tag`。 \ No newline at end of file From 7ea9dd5d48c1b260af805aafc02e040537cc2057 Mon Sep 17 00:00:00 2001 From: liguobin Date: Fri, 25 Sep 2020 15:23:11 +0800 Subject: [PATCH 2/5] change --- _zh-cn/overviews/reflection/typetags-manifests.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/_zh-cn/overviews/reflection/typetags-manifests.md b/_zh-cn/overviews/reflection/typetags-manifests.md index 5434ad6fab..0ed3799a3e 100644 --- a/_zh-cn/overviews/reflection/typetags-manifests.md +++ b/_zh-cn/overviews/reflection/typetags-manifests.md @@ -21,9 +21,9 @@ permalink: /overviews/reflection/:title.html Scala类型的完整类型描述符。例如,`TypeTag[List[String]]`包含所有类型信息,在本例中是类型`scala.List[String]`。 2. `scala.reflect.ClassTag`。 -Scala类型的部分类型描述符。例如,`ClassTag[List[String]]`只包含已删除的类类型信息,在本例中为`scala.collection.immutable.List`。`ClassTag`只提供对类型的运行时类的访问。类似于`scala.reflect.ClassManifest`。 +Scala类型的部分类型描述符。例如,`ClassTag[List[String]]`只包含已擦除、关于类的类型信息,在本例中为`scala.collection.immutable.List`。`ClassTag`只提供对类型的运行时类的访问。其类似于`scala.reflect.ClassManifest`。 -3. `scala.reflect.api.TypeTags#WeakTypeTag`. +3. `scala.reflect.api.TypeTags#WeakTypeTag`。 抽象类型的类型描述符(参见下面相应的小节)。 ## 获取`TypeTag` @@ -48,7 +48,7 @@ Scala类型的部分类型描述符。例如,`ClassTag[List[String]]`只包含 ### 使用类型为`TypeTag[T]`、`ClassTag[T]`或`WeakTypeTag[T]`的隐式参数 -与`Manifest`一样,实际上可以 _请求_ 编译器生成`TypeTag`。这只需指定一个类型为`TypeTag[T]`的隐式 _票据_ 参数即可完成。如果编译器在隐式搜索期间找不到匹配的隐式值,它将自动生成一个`TypeTag[T]`。 +与`Manifest`一样,实际上可以 _请求_ 编译器生成`TypeTag`。这只需指定一个类型为`TypeTag[T]`的隐式 _证据_ 参数即可完成。如果编译器在隐式搜索期间找不到匹配的隐式值,它将自动生成一个`TypeTag[T]`。 _注意_:这通常是通过在方法上使用隐式参数来实现的,并且只能在类上。 From 9bbfd1d0046e0e7eb628252328d40c46a9c86d6e Mon Sep 17 00:00:00 2001 From: liguobin Date: Fri, 25 Sep 2020 17:58:30 +0800 Subject: [PATCH 3/5] fix url --- _zh-cn/overviews/reflection/typetags-manifests.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/_zh-cn/overviews/reflection/typetags-manifests.md b/_zh-cn/overviews/reflection/typetags-manifests.md index 0ed3799a3e..e802a735cc 100644 --- a/_zh-cn/overviews/reflection/typetags-manifests.md +++ b/_zh-cn/overviews/reflection/typetags-manifests.md @@ -1,13 +1,13 @@ --- layout: multipage-overview -title: TypeTags and Manifests +title: TypeTags 和 Manifests partof: reflection overview-name: Reflection num: 5 -languages: [ja, zh-cn] -permalink: /overviews/reflection/:title.html +languages: zh-cn +permalink: /zh-cn/overviews/reflection/:title.html --- 与其他JVM语言一样,Scala的类型在运行时被擦除。这意味着,如果要检查某个实例的运行时类型,则可能无法访问Scala编译器在编译时可用的所有类型信息。 From 7ed67a7c3db07035d5d134409ecb13e2df7dd326 Mon Sep 17 00:00:00 2001 From: liguobin Date: Fri, 25 Sep 2020 18:10:39 +0800 Subject: [PATCH 4/5] fix url --- _zh-cn/overviews/reflection/thread-safety.md | 1 - _zh-cn/overviews/reflection/typetags-manifests.md | 1 - 2 files changed, 2 deletions(-) diff --git a/_zh-cn/overviews/reflection/thread-safety.md b/_zh-cn/overviews/reflection/thread-safety.md index d191848766..82e88593ef 100644 --- a/_zh-cn/overviews/reflection/thread-safety.md +++ b/_zh-cn/overviews/reflection/thread-safety.md @@ -7,7 +7,6 @@ overview-name: Reflection num: 6 language: zh-cn -permalink: /zh-cn/overviews/reflection/:title.html --- EXPERIMENTAL diff --git a/_zh-cn/overviews/reflection/typetags-manifests.md b/_zh-cn/overviews/reflection/typetags-manifests.md index e802a735cc..b76a333ce0 100644 --- a/_zh-cn/overviews/reflection/typetags-manifests.md +++ b/_zh-cn/overviews/reflection/typetags-manifests.md @@ -7,7 +7,6 @@ overview-name: Reflection num: 5 languages: zh-cn -permalink: /zh-cn/overviews/reflection/:title.html --- 与其他JVM语言一样,Scala的类型在运行时被擦除。这意味着,如果要检查某个实例的运行时类型,则可能无法访问Scala编译器在编译时可用的所有类型信息。 From d8efaee6146dae84e496a531a5763d91782b8c1a Mon Sep 17 00:00:00 2001 From: liguobin Date: Fri, 25 Sep 2020 18:21:45 +0800 Subject: [PATCH 5/5] fix url --- _zh-cn/overviews/reflection/thread-safety.md | 1 - _zh-cn/overviews/reflection/typetags-manifests.md | 1 - 2 files changed, 2 deletions(-) diff --git a/_zh-cn/overviews/reflection/thread-safety.md b/_zh-cn/overviews/reflection/thread-safety.md index 82e88593ef..86acc1c247 100644 --- a/_zh-cn/overviews/reflection/thread-safety.md +++ b/_zh-cn/overviews/reflection/thread-safety.md @@ -5,7 +5,6 @@ partof: reflection overview-name: Reflection num: 6 - language: zh-cn --- diff --git a/_zh-cn/overviews/reflection/typetags-manifests.md b/_zh-cn/overviews/reflection/typetags-manifests.md index b76a333ce0..0830e50839 100644 --- a/_zh-cn/overviews/reflection/typetags-manifests.md +++ b/_zh-cn/overviews/reflection/typetags-manifests.md @@ -5,7 +5,6 @@ partof: reflection overview-name: Reflection num: 5 - languages: zh-cn ---