简体   繁体   English

什么是何时使用Scala的forSome关键字?

[英]What is and when to use Scala's forSome keyword?

What is the difference between List[T] forSome {type T} and List[T forSome {type T}] ? List[T] forSome {type T}List[T forSome {type T}]什么List[T forSome {type T}] How do I read them in "English"? 我如何用“英语”阅读它们? How should I grok the forSome keyword? 我应该如何神交 forSome关键字? What are some practical uses of forSome ? forSome一些实际用途是forSome What are some useful practical and more complex than simple T forSome {type T} usages? 什么是有用的实用和复杂的简单T forSome {type T}用法?

There are a lot of questions here, and most of them have been addressed pretty thoroughly in the answers linked in the comments above, so I'll respond to your more concrete first question. 这里有很多问题,其中大部分已经在上面评论中链接的答案中得到了相当彻底的解决,所以我会回答你更具体的第一个问题。

There's no real meaningful difference between List[T] forSome { type T } and List[T forSome { type T }] , but we can see a difference between the following two types: List[T] forSome { type T }List[T forSome { type T }]之间没有真正有意义的区别,但我们可以看到以下两种类型之间的区别:

class Foo[A]

type Outer = List[Foo[T]] forSome { type T }
type Inner = List[Foo[T] forSome { type T }]

We can read the first as "a list of foos of T , for some type T ". 我们可以将第一个读作“ T的foos列表,对于某些类型T ”。 There's a single T for the entire list. 整个列表中只有一个T The second, on the other hand, can be read as "a list of foos, where each foo is of T for some T ". 第二,在另一方面,可以理解为“FOOS的列表,其中每个foo是的T一些T ”。

To put it another way, if we've got a list outer: Outer , we can say that "there exists some type T such that outer is a list of foos of T ", where for a list of type Inner , we can only say that "for each element of the list, there exists some T such that that element is a foo of T ". 换句话说,如果我们有一个outer: Outer列表outer: Outer ,我们可以说“存在一些类型T ,使得outerT的foos列表”,其中对于Inner类型的列表,我们只能说“对于列表的每个元素,存在一些T ,使得该元素是T的foo”。 The latter is weaker—it tells us less about the list. 后者较弱 - 它告诉我们较少的清单。

So, for example, if we have the following two lists: 因此,例如,如果我们有以下两个列表:

val inner: Inner = List(new Foo[Char], new Foo[Int])
val outer: Outer = List(new Foo[Char], new Foo[Int])

The first will compile just fine—each element of the list is a Foo[T] for some T . 第一个将编译得很好 - 列表中的每个元素对于某些T来说都是Foo[T] The second won't compile, since there's not some T such that each element of the list is a Foo[T] . 第二个不会编译,因为没有一些T这样列表中的每个元素都是Foo[T]

Attention: ( Update 2016-12-08 ) The forSome keyword is very likely going away with Scala 2.13 or 2.14, according to Martin Odersky's talk on the ScalaX 2016. Replace it with path dependent types or with anonymous type attributes ( A[_] ). 注意:( 更新2016-12-08 )根据Martin Odersky关于ScalaX 2016的讨论,forSome关键字很可能会与Scala 2.13或2.14一起消失。用路径依赖类型或匿名类型属性替换它( A[_] )。 This is possible in most cases. 在大多数情况下这是可能的。 If you have an edge case where it is not possible, refactor your code or loosen your type restrictions. 如果您的边缘情况不可能,请重构您的代码或放宽您的类型限制。

How to read "forSome" (in an informal way) 如何阅读“forSome”(以非正式的方式)

Usually when you use a generic API, the API guarantees you, that it will work with any type you provide (up to some given constraints). 通常当您使用通用API时,API会保证您可以使用您提供的任何类型(最多一些给定的约束)。 So when you use List[T] , the List API guarantees you that it will work with any type T you provide. 因此,当您使用List[T] ,List API会保证它可以与提供的任何类型T 使用

With forSome (so called existentially quantified type parameters) it is the other way round. 对于forSome (所谓的存在量化类型参数),它是相反的。 The API will provide a type (not you) and it guarantees you, it will work with this type it provided you. API将提供一种类型(不是你),它保证你,它将使用它提供给你的这种类型。 The semantics is, that a concrete object will give you something of type T . 语义是,具体对象会给你一些类型为T东西。 The same object will also accept the things it provided you. 同一个对象也会接受它为您提供的内容。 But no other object may work with these T s and no other object can provide you with something of type T . 但没有其他对象可以使用这些T s,没有其他对象可以为您提供T类型的东西。

The idea of "existentially quantified" is: There exists (at least) one type T (in the implementation) to fulfill the contract of the API. “存在量化”的概念是:存在(至少)一种类型T (在实现中)以履行API的合同。 But I won't tell you which type it is. 但我不会告诉你它是哪种类型。

forSome can be read similar: For some types T the API contract holds true. forSome可以读取类似:对于某些类型的T的API合同成立。 But it is not necessary true for all types T . 但对于所有类型的T都不一定如此。 So when you provide some type T (instead of the one hidden in the implementation of the API), the compiler cannot guarantee that you got the right T . 因此,当您提供某种类型的T (而不是在API的实现中隐藏的类型)时,编译器无法保证您获得了正确的T So it will throw a type error. 所以它会抛出一个类型错误。

Applied to your example 适用于您的示例

So when you see List[T] forSome {type T} in an API, you can read it like this: The API will provide you with a List of some unknown type T . 因此,当您在API中看到List[T] forSome {type T}时,您可以这样阅读:API将为您提供一些未知类型TList It will gladly accept this list back and it will work with it. 它很乐意接受这个列表,它将与它一起使用。 But it won't tell you, what T is. 但它不会告诉你, T是什么。 But you know at least, that all elements of the list are of the same type T . 但至少你知道,列表中的所有元素都是相同的类型T

The second one is a little bit more tricky. 第二个有点棘手。 Again the API will provide you with a List . API再次为您提供一个List And it will use some type T and not tell you what T is. 它会使用某种类型的T而不是告诉你T是什么。 But it is free to choose a different type for each element. 但是可以自由地为每个元素选择不同的类型。 A real world API would establish some constraints for T , so it can actually work with the elements of the list. 真实世界的API会为T建立一些约束,因此它实际上可以使用列表的元素。

Conclusion 结论

forSome is useful, when you write an API, where each object represents an implementation of the API. 当您编写API时, forSome很有用,其中每个对象代表API的实现。 Each implementation will provide you with some objects and will accept these objects back. 每个实现都将为您提供一些对象,并将接受这些对象。 But you can neither mix objects from different implementations nor can you create the objects yourself. 但是你既不能混合不同实现的对象,也不能自己创建对象。 Instead you must always use the corresponding API functions to get some objects that will work with that API. 相反,您必须始终使用相应的API函数来获取可与该API一起使用的一些对象。 forSome enables a very strict kind of encapsulation. forSome可以实现非常严格的封装。 You can read forSome in the following way: 您可以阅读forSome通过以下方式:

The API contract folds true for some types. 对于某些类型,API合约折叠为true。 But you don't know for which types it holds true. 但你不知道它适用于哪种类型。 Hence you cannot provide you own type and you cannot create your own objects. 因此,您无法提供自己的类型,也无法创建自己的对象。 You have to use the ones provided through the API that uses forSome . 您必须使用通过使用forSome的API提供的那些。

This is quite informal and might even be wrong in some corner cases. 这非常非正式,在某些极端情况下甚至可能是错误的。 But it should help you to grok the concept. 但它应该帮助你理解这个概念。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM