理解“type”关键字在 Scala 中的作用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19492542/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Understanding what 'type' keyword does in Scala
提问by Core_Dumped
I am new to Scala and I could not really find a lot about the typekeyword. I am trying to understand what the following expression may mean:
我是 Scala 的新手,我真的找不到很多关于这个type关键字的信息。我试图理解以下表达可能意味着什么:
type FunctorType = (LocalDate, HolidayCalendar, Int, Boolean) => LocalDate
FunctorTypeis some kind of an alias, but what does it signify?
FunctorType是某种别名,但它意味着什么?
回答by Marius Danila
Actually the typekeyword in Scala can do much more than just aliasing a complicated type to a shorter name. It introduces type members.
实际上type,Scala 中的关键字可以做的不仅仅是将复杂类型别名为较短的名称。它引入了类型成员。
As you know, a class can have field members and method members. Well, Scala also allows a class to have type members.
如您所知,一个类可以有字段成员和方法成员。嗯,Scala 也允许一个类有类型成员。
In your particular case typeis, indeed, introducing an alias that allows you to write more concise code. The type system just replaces the alias with the actual type when type-checking is performed.
在您的特定情况下type,确实引入了一个别名,使您可以编写更简洁的代码。类型系统只是在执行类型检查时用实际类型替换别名。
But you can also have something like this
但是你也可以有这样的东西
trait Base {
type T
def method: T
}
class Implementation extends Base {
type T = Int
def method: T = 42
}
Like any other member of a class, type members can also be abstract (you just don't specify what their value actually is) and can be overridden in implementations.
与类的任何其他成员一样,类型成员也可以是抽象的(您只是不指定它们的实际值)并且可以在实现中被覆盖。
Type members can be viewed as dual of generics since much of the things you can implement with generics can be translated into abstract type members.
类型成员可以被视为泛型的对偶,因为你可以用泛型实现的很多东西都可以转换为抽象类型成员。
So yes, they can be used for aliasing, but don't limit them to just this, since they are a powerful feature of Scala's type system.
所以是的,它们可以用于别名,但不要仅限于此,因为它们是 Scala 类型系统的强大功能。
Please see this excellent answer for more details:
有关更多详细信息,请参阅此优秀答案:
回答by Roland Ewald
Yes, the type aliasFunctorTypeis just a shorthand for
是的,类型别名FunctorType只是一个简写
(LocalDate, HolidayCalendar, Int, Boolean) => LocalDate
(LocalDate, HolidayCalendar, Int, Boolean) => LocalDate
Type aliases are often used to keep the rest of the code simple: you can now write
类型别名通常用于保持代码的其余部分简单:您现在可以编写
def doSomeThing(f: FunctorType)
which will be interpreted by the compiler as
这将被编译器解释为
def doSomeThing(f: (LocalDate, HolidayCalendar, Int, Boolean) => LocalDate)
This helps to avoid defining many custom types that are just tuples or functions defined on other types, for example.
例如,这有助于避免定义许多自定义类型,这些自定义类型只是在其他类型上定义的元组或函数。
There are also several other interesting use cases for type, as described for example in this chapterof Programming in Scala.
对于 ,还有其他几个有趣的用例type,例如在 Scala 编程这一章中描述的。
回答by Mehran
I liked the answer from Roland Ewaldsince he described with a very simple use case of type alias, and for more detail introduced a very nice tutorial. However, since another use case is introduced in this post named type members, I would like to mention the most practical use case of it, which I liked very much: (this part is taken from here:)
我喜欢Roland Ewald的回答, 因为他用一个非常简单的类型别名用例进行了描述,并且为了更详细地介绍了一个非常好的教程。但是,由于这篇文章中引入了另一个用例type members,我想提一下它最实际的用例,我非常喜欢:(这部分取自这里:)
Abstract Type:
摘要类型:
type T
T above says that this type that is going to be used, is unknown yet, and depending on the concrete subclass, it will be defined. The best way always for understanding the programming concepts is providing an example: Suppose you have the following scenario:
上面的 T 表示将要使用的这种类型是未知的,并且取决于具体的子类,它将被定义。始终理解编程概念的最佳方法是提供一个示例:假设您有以下场景:
Here you will get compilation error, because eat method in classes Cow and Tiger do not override the eat method in class Animal, because their parameter types are different. It's Grass in class Cow, and Meat in class Tiger vs. Food in class Animal which is super class and all subclasses must conform.
在这里你会得到编译错误,因为 Cow 和 Tiger 类中的eat 方法没有覆盖Animal 类中的eat 方法,因为它们的参数类型不同。Cow 类中的 Grass,Tiger 类中的 Meat vs. Animal 类中的 Food 是超类,所有子类都必须符合。
Now back to type abstraction, by the following diagram and simply adding a type abstraction, you can define the type of the input, in according subclass itself.
现在回到类型抽象,通过下图并简单地添加类型抽象,您可以根据子类本身定义输入的类型。
Now look at following codes:
现在看下面的代码:
val cow1: Cow = new Cow
val cow2: Cow = new Cow
cow1 eat new cow1.SuitableFood
cow2 eat new cow1.SuitableFood
val tiger: Tiger = new Tiger
cow1 eat new tiger.SuitableFood // Compiler error
Compiler is happy and we improve our design. We can feed our cow with cow.SuitableFood and compiler prevent us with feeding out cow with the food which is suitable for Tiger. But what if we want to make difference between the type of cow1 SuitableFood and cow2 SuitabeFood. In another word, it would be very handy in some scenarios if the path by which we reach to the type (of course via object) does basically matter. Thanks to the advanced features in scala, it is possible:
编译器很高兴,我们改进了我们的设计。我们可以用牛喂我们的牛。合适的食物和编译器阻止我们用适合老虎的食物喂牛。但是如果我们想要区分 cow1 适用食品和 cow2 SuitabeFood 的类型怎么办。换句话说,如果我们到达类型(当然是通过对象)的路径基本上很重要,那么在某些情况下它会非常方便。由于 scala 中的高级功能,它是可能的:
Path-dependent types:Scala objects can have types as members. The meaning of the type, depends on the path you use to access it. The path is determined by the reference to an object (aka an instance of a class). In order to implement this scenario, you need to define class Grass inside the Cow, i.e., Cow is the outer class and Grass is the inner class. The structure will be like this:
路径相关类型:Scala 对象可以将类型作为成员。类型的含义取决于您用来访问它的路径。路径由对对象(也就是类的实例)的引用确定。为了实现这个场景,需要在Cow内部定义类Grass,即Cow是外部类,Grass是内部类。结构将是这样的:
class Cow extends Animal {
class Grass extends Food
type SuitableFood = Grass
override def eat(food: this.SuitableFood): Unit = {}
}
class Tiger extends Animal {
class Meat extends Food
type SuitableFood = Meat
override def eat(food: this.SuitableFood): Unit = {}
}
Now if you try to compile this code:
现在,如果您尝试编译此代码:
1. val cow1: Cow = new Cow
2. val cow2: Cow = new Cow
3. cow1 eat new cow1.SuitableFood
4. cow2 eat new cow1.SuitableFood // compilation error
On line 4 you will see an error because Grass is now an inner class of Cow, therefore, to create an instance of Grass, we need a cow object and this cow object determines the path. So 2 cow objects give rise to 2 different path. In this scenario, cow2 only wants to eat food especially created for it. So:
在第 4 行你会看到一个错误,因为 Grass 现在是 Cow 的内部类,因此,要创建 Grass 的实例,我们需要一个 cow 对象,这个 cow 对象决定了路径。所以2个牛对象产生2个不同的路径。在这种情况下,cow2 只想吃专门为它创建的食物。所以:
cow2 eat new cow2.SuitableFood
Now everybody is happy :-)
现在每个人都很开心:-)
回答by sofiene zaghdoudi
Just an example to see how to use "type" as alias :
只是一个例子,看看如何使用“类型”作为别名:
type Action = () => Unit
The definition above defines Action to be an alias of the type of procedures(methodes) that take an empty parameter list and that return Unit.
上面的定义将 Action 定义为接受空参数列表并返回 Unit 的过程(方法)类型的别名。


