结构类型的实际用途?
结构类型是那些“哇,酷!”的类型之一。 Scala 的特点。然而,对于我能想到的每个例子,隐式转换和动态混合组合通常看起来是更好的匹配。它们的一些常见用途和/或何时合适的建议是什么?
Structural types are one of those "wow, cool!" features of Scala. However, For every example I can think of where they might help, implicit conversions and dynamic mixin composition often seem like better matches. What are some common uses for them and/or advice on when they are appropriate?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
除了极少数提供相同方法但不相关也不实现公共接口的类(例如,
close()
方法 -Source
),其一,不扩展Closeable
),我发现结构类型以其当前的限制没有用处。然而,如果它们更灵活,我可以写这样的东西:它将巧妙地处理数字类型。每当我认为结构类型可能对我有所帮助时,我都会碰壁。
编辑
尽管我自己发现结构类型没有用,但是编译器使用它来处理匿名类。例如:(
隐式)
toTimes(5)
产生的对象的类型为{ def times(block: => Unit) }
,即结构类型。我不知道 Scala 是否对每个匿名类都这样做——也许确实如此。唉,这就是为什么以这种方式为我的库提供缓慢的原因之一,因为结构类型使用反射来调用方法。人们应该使用真实的类,而不是匿名类,以避免在我的库中出现性能问题。
Aside from the rare case of classes which provide the same method but aren't related nor do implement a common interface (for example, the
close()
method --Source
, for one, does not extendCloseable
), I find no use for structural types with their present restriction. If they were more flexible, however, I could well write something like this:which would neatly handle numeric types. Every time I think structural types might help me with something, I hit that particular wall.
EDIT
However unuseful I find structural types myself, the compiler, however, uses it to handle anonymous classes. For example:
The object resulting from (the implicit)
toTimes(5)
is of type{ def times(block: => Unit) }
, ie, a structural type.I don't know if Scala does that for every anonymous class -- perhaps it does. Alas, that is one reason why doing pimp my library that way is slow, as structural types use reflection to invoke the methods. Instead of an anonymous class, one should use a real class to avoid performance issues in pimp my library.
结构类型是 Scala 中非常酷的构造。我使用它们来表示多个不相关的类型,这些类型共享一个属性,我想在这些属性上执行通用操作,而无需新的抽象级别。
我听过一些对应用程序架构严格要求的人提出反对结构类型的论点。他们认为在没有关联特征或父类型的情况下跨类型应用通用操作是危险的,因为这样你就留下了该方法应应用于开放式类型的规则。 Daniel 的
close()
示例很准确,但是如果您有另一种需要不同行为的类型怎么办?不了解架构的人可能会使用它并导致系统出现问题。Structural types are very cool constructs in Scala. I've used them to represent multiple unrelated types that share an attribute upon which I want to perform a common operation without a new level of abstraction.
I have heard one argument against structural types from people who are strict about an application's architecture. They feel it is dangerous to apply a common operation across types without an associative trait or parent type, because you then leave the rule of what type the method should apply to open-ended. Daniel's
close()
example is spot on, but what if you have another type that requires different behavior? Someone who doesn't understand the architecture might use it and cause problems in the system.我认为结构类型是您不经常需要的功能之一,但是当您需要它时,它会对您有很大帮助。结构类型真正发挥作用的一个领域是“改造”,例如,当您需要将多个没有源代码且不打算重用的软件粘合在一起时。但如果您发现自己经常使用结构类型,那么您可能做错了。
[编辑]
当然,隐式通常是可行的方法,但在某些情况下您不能这样做:假设您有一个可以使用方法修改的可变对象,但它隐藏了其状态的重要部分,一种“黑匣子”。然后你必须以某种方式处理这个对象。
结构类型的另一个用例是当代码依赖于命名约定而没有公共接口时,例如在机器生成的代码中。在 JDK 中我们也可以找到这样的东西,比如 StringBuffer / StringBuilder 对(其中公共接口 Appendable 和 CharSequence 是通用的)。
I think structural types are one of these features that you don't need that often, but when you need it, it helps you a lot. One area where structural types really shine is "retrofitting", e.g. when you need to glue together several pieces of software you have no source code for and which were not intended for reuse. But if you find yourself using structural types a lot, you're probably doing it wrong.
[Edit]
Of course implicits are often the way to go, but there are cases when you can't: Imagine you have a mutable object you can modify with methods, but which hides important parts of it's state, a kind of "black box". Then you have to work somehow with this object.
Another use case for structural types is when code relies on naming conventions without a common interface, e.g. in machine generated code. In the JDK we can find such things as well, like the StringBuffer / StringBuilder pair (where the common interfaces Appendable and CharSequence are way to general).
结构类型为静态链接语言提供了动态语言的一些好处,特别是松散耦合。如果您希望方法
foo()
调用类Bar
的实例方法,则不需要两个foo 共用的接口或基类()
和Bar
。您可以定义foo()
接受的结构类型,并且其Bar
不知道其存在。只要Bar
包含与结构类型签名匹配的方法,foo()
就能够调用。这很棒,因为您可以将
foo()
和Bar
放在不同的、完全不相关的库上,也就是说,没有共同的引用契约。这减少了链接要求,从而进一步有助于松散耦合。在某些情况下,结构类型可以用作 Adapter 模式的替代方案,因为它提供了优点如下:
Bar
实例传递给foo()
即可。Bar
才能调用其方法。这样,单个结构类型可以用于许多实际类型,而使用适配器则需要编写多个类 - 每个实际类型一个。与适配器相比,结构类型的唯一缺点是结构类型不能用于转换方法签名。因此,当签名不匹配时,您必须使用具有一些转换逻辑的适配器。我特别不喜欢编写“智能”适配器的代码,因为很多时候它们不仅仅是适配器,而且会导致复杂性增加。如果类客户端需要一些额外的方法,我更喜欢简单地添加这样的方法,因为它通常不会影响足迹。
Structural types gives some benefits of dynamic languages to a statically linked language, specifically loose coupling. If you want a method
foo()
to call instance methods of classBar
, you don't need an interface or base-class that is common to bothfoo()
andBar
. You can define a structural type thatfoo()
accepts and whoseBar
has no clue of existence. As long asBar
contains methods that match the structural type signatures,foo()
will be able to call.It's great because you can put
foo()
andBar
on distinct, completely unrelated libraries, that is, with no common referenced contract. This reduces linkage requirements and thus further contributes for loose coupling.In some situations, a structural type can be used as an alternative to the Adapter pattern, because it offers the following advantages:
Bar
instance tofoo()
.Bar
so it can call its methods. This way, a single structural type can be used for many actual types, whereas with adapter it's necessary to code multiple classes - one for each actual type.The only drawback of structural types compared to adapters is that a structural type can't be used to translate method signatures. So, when signatures doesn't match, you must use adapters that will have some translation logic. I particularly don't like to code "intelligent" adapters because in many times they are more than just adapters and cause increased complexity. If a class client needs some additional method, I prefer to simply add such method, since it usually doesn't affect footprint.