【问题标题】:Play Framework 2 - Scala template: How to call a specific method on a generic object?Play Framework 2 - Scala 模板:如何在通用对象上调用特定方法?
【发布时间】:2023-03-30 07:24:01
【问题描述】:

我在 Java 应用程序中使用 Play Framework 2.1.5。

我有一个视图组件,它采用通用对象列表作为参数。在这个组件中,我想迭代列表并获取每个元素的一些属性。

这看起来像这样:

@(elements: List[_])

@for((element, i) <- elements.view.zipWithIndex) {
    @i
    @element.id
    @element.name
}

(我需要这 3 个值)

当然,element.idelement.name 不会编译,即使我放在列表中的对象类型包含这些方法。所以我这样做了:

@for((element, i) <- elements.view.zipWithIndex) {
    @defining(
        ViewsUtils.getGenericElementId(element),
        ViewsUtils.getGenericElementName(element)) {
            case (id, name, something) =>
                @i
                @id
                @name
        }
}

在 Java 实用程序类中:

public final class ViewsUtils {

    public static String getGenericElementId(Object object) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        return object.getClass().getMethod("getId").invoke(object).toString();
    }

    public static String getGenericElementName(Object object) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        return object.getClass().getMethod("getName").invoke(object).toString();
    }
}

这可行,但我知道这是不对的,因为如果我放入列表中的对象类型不存在这些方法之一,它可能会引发 RuntimeException。

这是我的假设:

  1. 铸造元素

  2. 使用继承

  3. 因为我只需要每个对象的 2 个属性(id 和名称),我可以使用地图,但我需要循环的索引(是否可以从地图中获取它?)它会如果我需要 2 个以上的属性,那就不行了。

  4. 也许 Scala 为这类东西提供了语法。

或者我只是看错了方向。

感谢您的帮助。

【问题讨论】:

  • 为什么不传递@(elements: List[GenericObject])

标签: scala functional-programming playframework-2.0 generic-programming scala-template


【解决方案1】:

好的,评论有点过分,所以我会冒险将其发布为答案。

假设你不希望得到RuntimeException,你提到你的对象实现了一些接口(或混合一个特征,就像在 Scala 中所说的那样)是有道理的,所以你不会冒险得到一个异常并且没有更多需要反思才能获得价值。

假设,你声明了这样一个特征:

trait GenericObject {
  val id: Long
  val name: String
}

然后你声明一些案例类:

case class A(id: Long, name: String, someOtherField: SomeType) extends GenericObject {
  //your implementation
}

case class B(id: Long, name: String) extends GenericObject

case class C(id: Long, name: String) extends B(id, name)

现在您可以像这样更改您的模板:

@(elements: List[GenericObject])

@for((element, i) <- elements.view.zipWithIndex) {
  @i
  @element.id
  @element.name
}

您应该将GenericObjects 的列表传递给您的模板:

val myObjects: List[GenericObject] = List(A(1, "A name"), B(2, "B name"), C(3, "C name"))
Ok(your_template.scala.html(myObjects))

【讨论】:

  • 是的,这将是一个不错的解决方案。我会让这个没有答案几天,看看是否有任何其他建议,但这是我正在寻找的。非常感谢。
  • 有个小问题:我用的是Java。如果我理解正确,Scala 中的 trait 类似于 - 但不如 Java 中的接口强大。我只能声明必须实现的方法,而不是属性。因此,我必须将用于直接访问我的属性的新方法声明为公共的。也许我太需要了。
  • @Thomas 如果您正在使用 Java,您可以坚持使用 Java。我认为您想要的是使 GenericObject 成为一个抽象类。与 serejja 的答案相同,但 GenericObject 是一个抽象类,带有您的 idname 字段。
  • 我想到了,但我正在使用的对象是实体 bean。我会尝试继承,但对于我认为非常简单的事情来说,它变得太复杂了。你不觉得吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多