scala 从案例类中获取字段名称列表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31189754/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 07:19:28  来源:igfitidea点击:

Get field names list from case class

scala

提问by Alexander Kondaurov

I need to get only field names of case class. I'm not interested in its values. I thought getClass.getDeclaredFields.map(_.getName)would return a list of field names.

我只需要获取案例类的字段名称。我对它的价值不感兴趣。我认为getClass.getDeclaredFields.map(_.getName)会返回一个字段名称列表。

scala> case class User(id: Int, name: String)
defined class User

scala> User.getClass.getDeclaredFields
res14: Array[java.lang.reflect.Field] = Array(public static final User$ User$.MODULE$)

scala> User.getClass.getDeclaredFields.toList
res15: List[java.lang.reflect.Field] = List(public static final User$ User$.MODULE$)

scala> val user = User(1, "dude")
user: User = User(1,dude)

scala> user.getClass.getDeclaredFields.toList
res16: List[java.lang.reflect.Field] = List(private final int User.id, private final java.lang.String User.name)

What is this User$.MODULE$? What's that?

这个 User$.MODULE$ 是什么?那是什么?

Method getDeclaredFields works fine when you have an instance of a case class, but I don't want to create an instance in order to get only fields.

当您有一个案例类的实例时,方法 getDeclaredFields 工作正常,但我不想创建一个实例来仅获取字段。

Why this isn't true: User.getClass.getDeclaredFields.map(_.getName) == List("id", "name")?

为什么这不是真的: User.getClass.getDeclaredFields.map(_.getName) == List("id", "name")

回答by Dia Kharrat

By using User.getClass, you are referring to the class companion object that Scala by default creates for the case class, and not the case class itself. To get the class object of the case class, use classOf[User].

通过使用User.getClass,您指的是 Scala 默认为案例类创建的类伴侣对象,而不是案例类本身。要获取案例类的类对象,请使用classOf[User].

Alternatively, you could use Scala's reflection API to get the metadata of a case class, which gives you much more information:

或者,您可以使用 Scala 的反射 API 来获取案例类的元数据,它为您提供更多信息:

import scala.reflect.runtime.universe._

def classAccessors[T: TypeTag]: List[MethodSymbol] = typeOf[T].members.collect {
  case m: MethodSymbol if m.isCaseAccessor => m
}.toList

Test in sbt console:

在 sbt 控制台中测试:

scala> case class User(name: String, age: Int)
defined class User

scala> classAccessors[User]
res0: List[reflect.runtime.universe.MethodSymbol] = List(value age, value name)

回答by Xavier Guihot

Starting Scala 2.13, case classes(which are an implementation of Product) are now provided with a productElementNamesmethod which returns an iterator over their field's names.

开始Scala 2.13case classes(这是 的实现Product)现在提供了一个productElementNames方法,该方法返回其字段名称的迭代器。

From an instance of the case class (let's say case class Person(name: String, age: Int)), one can retrieve a Listof its fields:

从 case 类的实例(比方说case class Person(name: String, age: Int)),可以检索List其字段中的一个:

Person("hello", 28).productElementNames.toList
// List[String] = List(name, age)

回答by drexin

User.getClassdoes not give you the equivalent of User.classin Java, but it gives you the class of the companion object of the Userclass. You can retrieve the Classobject of Userwith classOf[User].

User.getClass没有给你User.class在 Java 中的等价物,但它给你类的伴生对象的User类。您可以检索with的Class对象。UserclassOf[User]

edit: Oh and the User$.MODULE$is an accessor to the singleton instance that is used internally. Think of it as the equivalent to MyClass.INSTANCEwhen you are writing singletons in Java.

编辑:哦,User$.MODULE$它是内部使用的单例实例的访问器。把它想象成MyClass.INSTANCE你在 Java 中编写单例时的等价物。

回答by Andrey Tyukin

If you are also wondering why some Scala-reflection code is not compiling any more, here is a crude solution with the good ol' Java reflection (which, apparently, has been working in exactly the same way since approx. year 1300 BC):

如果您还想知道为什么一些 Scala 反射代码不再编译,这里有一个带有好的 ol' Java 反射的粗略解决方案(显然,自大约公元前 1300 年以来,它一直以完全相同的方式工作):

case class User(b: Int, a: String)
val u = User(42, "JohnDoe")

classOf[User]
.getDeclaredFields
.map{ f => 
  f.setAccessible(true)
  val res = (f.getName, f.get(u))
  f.setAccessible(false)
  res
}

It will get both the names and the values:

它将获得名称和值:

Array((b,42), (a,bob))

The order seems to be the same as in the constructor.

顺序似乎与构造函数中的顺序相同。

回答by Devendra Parhate

If you are using Spark, this the easiest way to get fields:

如果您使用的是 Spark,这是获取字段的最简单方法:

val cols = Seq(CaseClassModel()).toDF().columns

Note: The CaseClassModel should have fields initialized

注意:CaseClassModel 应该初始化字段