案例类上的“productElement(i)”是否使用反射?

发布于 2024-09-29 22:25:38 字数 375 浏览 1 评论 0原文

考虑以下 Scala 片段:

case class Foo(v1: String, v2: Int, v3: Any)

def inspect(p: Product) =
  (0 until p.productArity).foreach(i => println(p.productElement(i)))

inspect(Foo("Moin", 77, null))

此处调用 inspect() 是否意味着使用反射(以任何方式)?

我希望能够以某种方式访问​​案例类的字段,而不必显式引用它们,例如通过 foo.v1 并且我喜欢一种不需要反射的解决方案,因为我预计这会带来一些开销。

Considering the following Scala snippet:

case class Foo(v1: String, v2: Int, v3: Any)

def inspect(p: Product) =
  (0 until p.productArity).foreach(i => println(p.productElement(i)))

inspect(Foo("Moin", 77, null))

Does the invocation of inspect() here means that reflection is used (in whatever way)?

I'd like to somehow be able to access the fields of a case-class without having to explicitly refer to them, e.g. by foo.v1 and I'd favour a solution that does not require reflection since I expect that it entails some overhead.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

小兔几 2024-10-06 22:25:38

产品元素不会使用反射。这是一个编译器技巧。在类之前添加 case 不仅仅会创建一个伴生对象(使用 apply 方法等,请参阅 http ://www.scala-lang.org/node/258),它还从特征 Product 扩展了该类。编译器创建抽象方法productArity 和productElement 的实现。

scalac -print Foo.scala 的输出显示了这一点:

... case class Foo extends java.lang.Object with ScalaObject with Product {
...
override def productArity(): Int = 3;
override def productElement(x$1: Int): java.lang.Object = {
  <synthetic> val temp6: Int = x$1;
  (temp6: Int) match {
    case 0 => {
      Foo.this.v1()
    }
    case 1 => {
      scala.Int.box(Foo.this.v2())
    }
    case 2 => {
      Foo.this.v3()
    }
    case _ => {
      throw new java.lang.IndexOutOfBoundsException(scala.Int.box(x$1).toString())
    }
  }
};
...
}

如果您想在不反射的情况下访问字段,您可以使用特征 Product 中的方法productElement

scala> case class Foo(v1: String, v2: Int, v3: Any)
defined class Foo

scala> val bar = Foo("Moin", 77, null)
bar: Foo = Foo(Moin,77,null)

scala> bar.productElement(0)
res4: Any = Moin

scala> bar.productElement(1)
res5: Any = 77

scala> bar.productElement(2)
res6: Any = null

No reflection will be used for the productElement. It's a compiler trick. Adding case before a class doesn't just create a companion object (with apply method and so on, see http://www.scala-lang.org/node/258), it also extends the class from the trait Product. The compiler creates implementations of the abstract methods productArity and productElement.

The output of scalac -print Foo.scala shows it:

... case class Foo extends java.lang.Object with ScalaObject with Product {
...
override def productArity(): Int = 3;
override def productElement(x$1: Int): java.lang.Object = {
  <synthetic> val temp6: Int = x$1;
  (temp6: Int) match {
    case 0 => {
      Foo.this.v1()
    }
    case 1 => {
      scala.Int.box(Foo.this.v2())
    }
    case 2 => {
      Foo.this.v3()
    }
    case _ => {
      throw new java.lang.IndexOutOfBoundsException(scala.Int.box(x$1).toString())
    }
  }
};
...
}

If you want to access to the fields without reflection, you can use the method productElement from the trait Product

scala> case class Foo(v1: String, v2: Int, v3: Any)
defined class Foo

scala> val bar = Foo("Moin", 77, null)
bar: Foo = Foo(Moin,77,null)

scala> bar.productElement(0)
res4: Any = Moin

scala> bar.productElement(1)
res5: Any = 77

scala> bar.productElement(2)
res6: Any = null
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文