为什么这个映射函数不给出特征的简单名称
Why this map function does not give traits' simple names
我尝试获取所有特征的名称 class 使用 getInterfaces
扩展,其中 returns 特征名称数组。当我手动访问数组的每个成员时,方法 getName
returns 像这样的简单名称
trait A
trait B
class C() extends A, B
val c = C()
val arr = c.getClass.getInterfaces
arr(0).getName // : String = A
arr(1).getName // : String = B
但是,当我在 arr
上使用 map
函数时。结果数组包含特征名称的神秘版本
arr.map(t => t.getName) // : Array[String] = Array(repl$.rs$line$A, repl$.rs$line$B)
这个问题的目的不是关于如何获得包含简单名称的结果数组(为此,我可以只使用 arr.map(t => t.getSimpleName)
。)我很好奇的是为什么访问数组手动和使用 map
不会产生兼容的结果。我认为这两种方式是等价的吗?
问题不在于 map
而在于 Array
,尤其是它的 toString
方法 (这是不使用 [=13 的众多原因之一=]).
实际上,在这种情况下,情况更糟,因为 REPL 做了一些奇怪的事情来尝试漂亮打印 Arrays
,在这种情况下效果不佳 (而且,恕我直言, 只会增加混乱)
您可以像这样直接调用 mkString
来解决这个问题:
val arr = c.getClass.getInterfaces
val result = arr.map(t => t.getName)
val text = result.mkString("[", ", ", "]")
println(text)
但是,我宁愿建议根本不使用 Array
,而是尽快将其转换为适当的集合 (例如 List
)可能像:
val interfaces = c.getClass.getInterfaces.toList
interfaces .map(t => t.getName)
Note: About the other reasons for not using Arrays
- They are mutable.
- Thet are invariant.
- They are not part of the collections hierarchy thus you can't use them on generic methods (well, you actually can but that requires more tricks).
- Their
equals
is by reference instead of by value.
我相信你 运行 Scala REPL 或 Ammonite 中的东西。
当你定义:
trait A
trait B
class C() extends A, B
classes A
、B
和 C
未在根包的顶层定义。 REPL 创建一些隔离环境,编译代码并将结果加载到一些内部“匿名”命名空间中。
但事实并非如此。此字节码的创建位置反映在 class 名称中。所以显然有一些与
相似(不一定相同)的东西
// repl$ suggest object
object repl {
// .rs sound like nested object(?)
object rs {
// $line sounds like nested class
class line { /* ... */ }
// $line sounds like the first anonymous instance of line
new line { trait A }
// import from `above
// $line sounds like the second anonymous instance of line
new line { trait B }
// import from above
//...
}
}
这是因为 REPL 中的范围界定工作方式:新行创建一个新范围,其中包含以前的定义和新添加的定义(可能掩盖了一些旧定义)。这可以通过创建一段新代码作为新匿名 class 的代码、编译它、读入 class 路径、实例化并导入其内容来实现。通过将每个新行放入单独的 class REPL 能够按步骤编译和 运行 事情,而无需等待您告诉它脚本已完成并关闭。
当您使用 运行 时间反射访问 class 名称时,您会看到事物评估方式的人工产物。一条路径可能会通过 REPL 美化器来隐藏这些东西,而另一条路径会绕过它们,因此您可以看到 JVM 看到的原始值。
我尝试获取所有特征的名称 class 使用 getInterfaces
扩展,其中 returns 特征名称数组。当我手动访问数组的每个成员时,方法 getName
returns 像这样的简单名称
trait A
trait B
class C() extends A, B
val c = C()
val arr = c.getClass.getInterfaces
arr(0).getName // : String = A
arr(1).getName // : String = B
但是,当我在 arr
上使用 map
函数时。结果数组包含特征名称的神秘版本
arr.map(t => t.getName) // : Array[String] = Array(repl$.rs$line$A, repl$.rs$line$B)
这个问题的目的不是关于如何获得包含简单名称的结果数组(为此,我可以只使用 arr.map(t => t.getSimpleName)
。)我很好奇的是为什么访问数组手动和使用 map
不会产生兼容的结果。我认为这两种方式是等价的吗?
问题不在于 map
而在于 Array
,尤其是它的 toString
方法 (这是不使用 [=13 的众多原因之一=]).
实际上,在这种情况下,情况更糟,因为 REPL 做了一些奇怪的事情来尝试漂亮打印 Arrays
,在这种情况下效果不佳 (而且,恕我直言, 只会增加混乱)
您可以像这样直接调用 mkString
来解决这个问题:
val arr = c.getClass.getInterfaces
val result = arr.map(t => t.getName)
val text = result.mkString("[", ", ", "]")
println(text)
但是,我宁愿建议根本不使用 Array
,而是尽快将其转换为适当的集合 (例如 List
)可能像:
val interfaces = c.getClass.getInterfaces.toList
interfaces .map(t => t.getName)
Note: About the other reasons for not using
Arrays
- They are mutable.
- Thet are invariant.
- They are not part of the collections hierarchy thus you can't use them on generic methods (well, you actually can but that requires more tricks).
- Their
equals
is by reference instead of by value.
我相信你 运行 Scala REPL 或 Ammonite 中的东西。
当你定义:
trait A
trait B
class C() extends A, B
classes A
、B
和 C
未在根包的顶层定义。 REPL 创建一些隔离环境,编译代码并将结果加载到一些内部“匿名”命名空间中。
但事实并非如此。此字节码的创建位置反映在 class 名称中。所以显然有一些与
相似(不一定相同)的东西// repl$ suggest object
object repl {
// .rs sound like nested object(?)
object rs {
// $line sounds like nested class
class line { /* ... */ }
// $line sounds like the first anonymous instance of line
new line { trait A }
// import from `above
// $line sounds like the second anonymous instance of line
new line { trait B }
// import from above
//...
}
}
这是因为 REPL 中的范围界定工作方式:新行创建一个新范围,其中包含以前的定义和新添加的定义(可能掩盖了一些旧定义)。这可以通过创建一段新代码作为新匿名 class 的代码、编译它、读入 class 路径、实例化并导入其内容来实现。通过将每个新行放入单独的 class REPL 能够按步骤编译和 运行 事情,而无需等待您告诉它脚本已完成并关闭。
当您使用 运行 时间反射访问 class 名称时,您会看到事物评估方式的人工产物。一条路径可能会通过 REPL 美化器来隐藏这些东西,而另一条路径会绕过它们,因此您可以看到 JVM 看到的原始值。