scala - 返回内部类对象的列表

标签 scala

我将从 Java 转向 Scala。我想创建一个 Outer 类,它定义 (1) 一个内部 Inner 案例类和 (2) 一个返回 Inner 列表的方法对象。请注意,在 Java 中,内部类的类型明确是 Outer.Inner

我发现有两种方法可以引用内部类的类型:outerObject.InnerOuter#Inner,如所讨论的here我应该使用哪个来返回内部对象的列表?

例如,我可以像这样实现我的 Scala 代码:

// Implementation 1
class Outer {
    case class Inner(id: String)
    def build(input: List[String]): List[Inner] = {
        var result = scala.collection.mutable.ListBuffer[Inner]()
        input.foreach { s =>
            val inner = Inner(s)
            result += inner
        }
        result.toList
    }
}

或者像这样:

// Implementation 2
class Outer {
    case class Inner(id: String)
    def build(input: List[String]): List[Outer#Inner] = {
        var result = scala.collection.mutable.ListBuffer[Outer#Inner]()
        input.foreach { s =>
            val inner = Inner(s)
            result += inner
        }
        result.toList
    }
}

唯一的区别是 build() 返回 List[Inner]List[Outer#Inner]

假设我的代码的调用者运行以下代码:

val input: List[String] = List("A", "B", "C")
val outer = new Outer()
val output = outer.build(input)

然后对于实现 1,调用者看到的输出是:

output: List[outer.Inner] = List(Inner(A), Inner(B), Inner(C))

而对于实现 2,调用者会看到:

output: List[Outer#Inner] = List(Inner(A), Inner(B), Inner(C))

Scala 中哪种是首选(惯用)方法?

相关问题:

最佳答案

欢迎来到Scala!

首先,有一种更干净、更有效的方法来创建实现,我在下面展示了这一点。

// Implementation 1
class Outer {
  case class Inner(id: String)
  def build(input: List[String]): List[Inner] = input.map(s => Inner(s))
}

// Implementation 2
class Outer {
  case class Inner(id: String)
  def build(input: List[String]): List[Outer#Inner] = input.map(s => Inner(s))
}

使用map意味着你不需要任何丑陋的var元素,也不需要构建一个ListBuffer将其转换为列表

至于哪个更惯用,这取决于您想要做什么。第一种形式返回依赖于路径Inner列表。它可以被限制与创建它的 Outer 实例一起使用。在第二种形式中,返回的 Inner 类型不能绑定(bind)到特定的 Outer 实例,但可以在any 的任何地方使用内部实例是可以接受的。因此,后者的限制性更大,而前者的限制性较小。考虑以下因素:

// Implementation 1
class Outer {
  case class Inner(id: String)
  def build(input: List[String]): List[Inner] = input.map(s => Inner(s))
  def getId(inner: Inner): String = inner.id
}

// Implementation 2
class Outer {
  case class Inner(id: String)
  def build(input: List[String]): List[Outer#Inner] = input.map(s => Inner(s))
  def getId(inner: Outer#Inner): String = inner.id
}

然后尝试评估每个实现的以下内容:

val input: List[String] = List("A", "B", "C")
val outer = new Outer()
val output = outer.build(input)
val outer2 = new Outer()
outer2.getId(output.head)

使用实现 1,您将在最后一条语句中收到类型不匹配错误,但实现 2 不会出现这种情况。

更新:我忘了提及这一点(可能是为了避免进一步混淆),但是路径相关版本是通用版本的子类型。 (即 this.InnerOuter#Inner 的子类型。)因此,您可以传递 路径相关 版本的 Inner 到需要 any Inner 的函数,但反之则不然。

也就是说,以下内容将起作用:

class Outer {
  case class Inner(id: String)
  def build(input: List[String]): List[Inner] = input.map(Inner)
  def getId(inner: Outer#Inner): String = inner.id
}

val input: List[String] = List("A", "B", "C")
val outer = new Outer()
val output = outer.build(input)
val outer2 = new Outer()
outer2.getId(output.head)

但这不会:

class Outer {
  case class Inner(id: String)
  def build(input: List[String]): List[Outer#Inner] = input.map(Inner)
  def getId(inner: Inner): String = inner.id
}

val input: List[String] = List("A", "B", "C")
val outer = new Outer()
val output = outer.build(input)
val outer2 = new Outer()
outer2.getId(output.head)

(请注意,我还在每个方法中使用了更简洁形式的 build 方法。)

所以,总结一下......

返回新 Inner 实例的函数(属于 Outer)应该返回路径相关形式,因为这也是一个子函数类型的通用形式,并提供最大的灵活性。 (但是,请记住,可以从 Outer 实例的控制范围之外创建可公开访问的 Inner 类实例,并且可以是调用者需要的任何类型。) p>

然而,更重要的是接受现有 Inner 实例时使用的类型签名:

  • 如果操作(属于 Outer 实例)在 Inner 实例与其自身(以及 Inner > 实例通常会维护对其 Outer 实例的引用),因此提供属于不同 OuterInner 将是错误的例如,那么您应该只接受路径相关形式。

  • 但是,如果该操作适用于任何 Inner 实例,包括接受方法不属于 Outer 的情况> 无论如何,那么它应该接受通用形式。

关于scala - 返回内部类对象的列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52508246/

相关文章:

java - ORM 支持不可变类

Scala - 按可选字段排序,最后没有值

scala - 如何在 typesafeconfig 中将 ConfigValue 转换为 List[ConfigObject]

scala - 如何访问和改变scala中的私有(private)字段?

java - (编译:compileIncremental) javac returned nonzero exit code

Scala 实数区间,整数区间

scala - Play Framework 2.6 Alpakka S3 文件上传

java - 使用 DynamoDBMapper 保存具有版本化属性的新项目

scala - 玩 scala - 通过 Guice Injector 实例注入(inject)依赖项

scala - 使用两个条件过滤列表并创建 map scala