结构类型的实际用途?

时间:2010-11-06 00:47:02

标签: scala

结构类型是其中之一“哇,很酷!” Scala的功能。但是,对于每个例子,我都可以想到它们可能会有什么帮助,隐式转换和动态混合组合通常看起来更好。它们的常见用途和/或适当的建议是什么?

4 个答案:

答案 0 :(得分:13)

除了提供相同方法但不相关的类的罕见情况,也没有实现公共接口(例如,close()方法 - Source,对于一个,不扩展Closeable),我发现结构类型没有用于它们目前的限制。但是,如果它们更灵活,我可以写出这样的东西:

def add[T: { def +(x: T): T }](a: T, b: T) = a + b

可以整齐地处理数字类型。每当我认为结构类型可能对我有所帮助时,我会碰到那个特定的墙。

修改

然而,我自己找不到结构类型,编译器然而,它使用它来处理匿名类。例如:

implicit def toTimes(count: Int) = new {
  def times(block: => Unit) = 1 to count foreach { _ => block }
}

5 times { println("This uses structural types!") }

由(隐式)toTimes(5)产生的对象属于{ def times(block: => Unit) }类型,即结构类型。

我不知道Scala是否会为每个匿名类做到这一点 - 也许确实如此。唉,这就是为什么pimp我的库这么慢的原因之一,因为结构类型使用反射来调用方法。不应该使用匿名类,而应该使用真正的类来避免pimp my library中的性能问题。

答案 1 :(得分:3)

结构类型是Scala中非常酷的结构。我使用它们来表示多个不相关的类型,这些类型共享一个属性,我希望在没有新的抽象级别的情况下执行常见的操作。

我从一个对应用程序架构严格的人那里听到了一个反对结构类型的论点。他们认为在没有关联特征或父类型的情况下跨类型应用常见操作是危险的,因为您将该方法应该应用于开放式的规则。丹尼尔close()的例子很明显,但是如果你有另一种需要不同行为的类型呢?不了解架构的人可能会使用它并导致系统出现问题。

答案 2 :(得分:2)

我认为结构类型是您经常不需要的这些功能之一,但需要它时,它会帮助您很多。结构类型真正发光的一个领域是“改装”,例如当你需要将几个软件粘在一起时,你没有源代码,也没有打算重用。但是如果你发现自己经常使用结构类型,那么你可能做错了。

<强> [编辑]

当然暗示通常是要走的路,但有些情况下你不能:想象你有一个可变的对象你可以用方法修改,但它隐藏了它的状态的重要部分,一种“黑盒子” ”。然后你必须以某种方式使用这个对象。

结构类型的另一个用例是当代码依赖于没有公共接口的命名约定时,例如在机器生成的代码中。在JDK中我们也可以找到这样的东西,比如StringBuffer / StringBuilder对(其中公共接口Appendable和CharSequence way 一般)。

答案 3 :(得分:1)

结构类型为静态链接语言提供动态语言的一些好处,特别是松散耦合。如果希望方法foo()调用类Bar的实例方法,则不需要foo()Bar共有的接口或基类。您可以定义foo()接受的结构类型,其Bar不存在线索。只要Bar包含与结构类型签名匹配的方法,foo()就可以调用。

这很棒,因为你可以将foo()Bar放在不同的,完全不相关的库上,也就是说,没有共同引用的契约。这降低了连杆要求,从而进一步促进松耦合。

在某些情况下,结构类型可以用作Adapter模式的替代,因为它具有以下优点:

  • 保留对象标识(适配器实例没有单独的对象,至少在语义级别)。
  • 您无需实例化适配器 - 只需将Bar实例传递给foo()
  • 您不需要实现包装器方法 - 只需在结构类型中声明所需的签名。
  • 结构类型不需要知道实际的实例类或接口,而适配器必须知道Bar,因此它可以调用其方法。这样,单个结构类型可以用于许多实际类型,而使用适配器则需要编写多个类 - 每个实际类型一个。

与适配器相比,结构类型的唯一缺点是结构类型不能用于转换方法签名。因此,当签名不匹配时,您必须使用具有某些转换逻辑的适配器。我特别不喜欢编写“智能”适配器,因为很多时候它们不仅仅是适配器而且会增加复杂性。如果类客户端需要一些额外的方法,我更喜欢简单地添加这样的方法,因为它通常不会影响占用空间。