我是Scala的新手,我无法真正找到关于type
关键字的很多信息。我试图理解以下表达式的含义:
type FunctorType = (LocalDate, HolidayCalendar, Int, Boolean) => LocalDate
FunctorType
是某种别名,但它的含义是什么?
答案 0 :(得分:178)
实际上,Scala中的type
关键字可以做的不仅仅是将复杂类型别名化为较短的名称。它引入了类型成员。
如您所知,类可以包含字段成员和方法成员。好吧,Scala还允许类具有类型成员。
在您的特定情况下,type
确实引入了一个别名,允许您编写更简洁的代码。在执行类型检查时,类型系统只是用实际类型替换别名。
但你也可以有这样的东西
trait Base {
type T
def method: T
}
class Implementation extends Base {
type T = Int
def method: T = 42
}
与类的任何其他成员一样,类型成员也可以是抽象的(您只是不指定它们的值实际是什么)并且可以在实现中被覆盖。
类型成员可以被视为泛型的双重性,因为可以使用泛型实现的大部分内容可以转换为抽象类型成员。
所以是的,它们可以用于别名,但不限于此,因为它们是Scala类型系统的强大功能。
有关详细信息,请参阅此优秀答案:
答案 1 :(得分:131)
是的,类型别名 FunctorType
只是
(LocalDate, HolidayCalendar, Int, Boolean) => LocalDate
类型别名通常用于保持代码的其余部分简单:您现在可以编写
def doSomeThing(f: FunctorType)
将由编译器解释为
def doSomeThing(f: (LocalDate, HolidayCalendar, Int, Boolean) => LocalDate)
这有助于避免定义许多自定义类型,例如,仅在其他类型上定义的元组或函数。
type
还有其他几个有趣的用例,例如在Scala中编程的this chapter中所述。
答案 2 :(得分:5)
只是一个例子,看看如何使用"输入"作为别名:
type Action = () => Unit
上面的定义将Action定义为采用空参数列表并返回Unit的过程类型(方法)的别名。
答案 3 :(得分:1)
我喜欢Roland Ewald的答案,因为他用一个非常简单的类型别名用例进行了描述,并且更详细地介绍了一个非常好的教程。 但是,由于在本帖子中介绍了它的另一个用例,即类型成员,因此,我想提及一下它最实用的用例,我非常喜欢它: (这部分摘自here:)
摘要类型:
type T
上面的T表示将要使用的这种类型还未知,并且将根据具体的子类进行定义。 始终了解编程概念的最佳方法是提供一个示例: 假设您具有以下情况:
在这里,您会得到编译错误,因为Cow和Tiger类中的eat方法不会覆盖Animal类中的eat方法,因为它们的参数类型不同。牛类是草,虎类是肉,动物类是食物,动物是超类,所有子类都必须符合。
现在回到类型抽象,通过下图并简单地添加类型抽象,您可以根据子类本身定义输入的类型。
现在看下面的代码:
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
编译器很高兴,我们改进了设计。我们可以用牛喂牛。SuitableFood和编译器阻止我们用适合老虎的食物喂牛。但是,如果我们想区分Cow1适合食品和Cow2吹牛食品的类型,该怎么办?换句话说,如果我们到达类型的路径(当然是通过对象)基本上很重要,那么在某些情况下将非常方便。借助scala中的高级功能,可以实现:
路径相关类型: Scala对象可以具有类型作为成员。类型的含义取决于您用来访问它的路径。路径由对对象(即类的实例)的引用确定。 为了实现此方案,您需要在Cow内部定义Grass类,即Cow是外部类,Grass是内部类。结构如下:
class Cow extends Animal {
class Grass extends Food
type SuitaleFood = Grass
override def eat(food: this.SuitableFood): Unit = {}
}
class Tiger extends Animal {
class Meat extends Food
type SuitaleFood = Meat
override def eat(food: this.SuitableFood): Unit = {}
}
现在,如果您尝试编译此代码:
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
在第4行,您将看到一个错误,因为Grass现在是Cow的一个内部类,因此,要创建Grass的实例,我们需要一个cow对象,而该cow对象将确定路径。因此,两个牛对象会产生两个不同的路径。 在这种情况下,cow2只想吃专门为其创建的食物。所以:
cow2 eat new cow2.SuitableFood
现在每个人都很高兴:-)