我将从 Java 转向 Scala。我想创建一个 Outer
类,它定义 (1) 一个内部 Inner
案例类和 (2) 一个返回 Inner
列表的方法对象。请注意,在 Java 中,内部类的类型明确是 Outer.Inner
。
我发现有两种方法可以引用内部类的类型:outerObject.Inner
或 Outer#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.Inner
是 Outer#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
实例的引用),因此提供属于不同Outer
的Inner
将是错误的例如,那么您应该只接受路径相关形式。但是,如果该操作适用于任何
Inner
实例,包括接受方法不属于Outer
的情况> 无论如何,那么它应该接受通用形式。
关于scala - 返回内部类对象的列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52508246/