scala.Enumerator.nextName
和.nextNameOrNull
目前已阅读:
/** The string to use to name the next created value. */
protected var nextName: Iterator[String] = _
private def nextNameOrNull =
if (nextName != null && nextName.hasNext) nextName.next() else null
随后调用 nextNameOrNull
以获取用于在枚举中创建的项目的名称。
此代码实际上是如何实现此目的的?
当我将其复制粘贴到一个简单的例子中时:
class MyBaseClass extends Serializable {
/** The string to use to name the next created value. */
protected var nextName: Iterator[String] = _
private def nextNameOrNull =
if (nextName != null && nextName.hasNext) nextName.next() else null
protected final def Value(): Val = Val(nextNameOrNull)
case class Val(name:String)
}
object MyObject extends MyBaseClass {
val myValue = Value
println("Hello from MyObject, myValue: " + myValue)
}
它打印:Hello from MyObject, myValue: Val(null)
而不是Val(myValue)
我需要添加什么才能使其正常工作?
答案 0 :(得分:4)
在Scala JVM中,Enumeration
uses reflection获取Value
返回null时已分配nextNameOrNull
的val的名称。
在Scala.js中,我们没有这种奢侈(没有反射支持)。因此,Scala.js编译器特殊情况 scala.Enumeration
,以便使用它的代码可以工作。
如果你想实现一些知道它所分配的val
名称的mdethod,请看看sbt的project
macro。 Scala的Enumerations可以从2.10开始实现,但是更老。
答案 1 :(得分:2)
nextNameOrNull
也不再有效 - 因为不推荐使用将一系列名称传递给构造函数。
这是使用原始scala的Enumeration
(不是scala-js中替换的那个)的2.11.2的执行:
scala> object MyObject extends Enumeration {
| val MyValue1, MyValue2 = Value
|
| println("nextName: " + nextName)
| }
defined object MyObject
scala> MyObject
nextName: null //still null
在构造函数中使用的2.10.x
nextName
中明确指定名称作为序列(在2.11.x
中删除):
@deprecated("Names should be specified individually or discovered via reflection", "2.10.0")
def this(initial: Int, names: String*) = {
this(initial)
this.nextName = names.iterator
}
}
现在删除了这个构造函数,nextName
只是一个死代码。 Scala使用populateNameMap()
为nameOf
提供名称(如果未指定:
private def populateNameMap() {
val fields = getClass.getDeclaredFields
def isValDef(m: JMethod) = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType)
// The list of possible Value methods: 0-args which return a conforming type
val methods = getClass.getMethods filter (m => m.getParameterTypes.isEmpty &&
classOf[Value].isAssignableFrom(m.getReturnType) &&
m.getDeclaringClass != classOf[Enumeration] &&
isValDef(m))
methods foreach { m =>
val name = m.getName
// invoke method to obtain actual `Value` instance
val value = m.invoke(this).asInstanceOf[Value]
// verify that outer points to the correct Enumeration: ticket #3616.
if (value.outerEnum eq thisenum) {
val id = Int.unbox(classOf[Val] getMethod "id" invoke value)
nmap += ((id, name))
}
}
}
所以它默认使用反射。您可以明确指定每个值的名称,如here所述。
我认为ScalaJs也是如此,排除它没有populateNameMap()
方法,因为JavaScript没有这种反射 - 所以非显式命名参数的结果是:
override def toString() =
if (name != null) name //only if you did `Value("explicitName")` somwhere inside enumeration
// Scala.js specific
else s"<Unknown name for enum field #$i of class ${getClass}>"
但是再一次,nextNameOrNull
在Scala和Scala-Js中都死了 - 它总是返回null。