Scala,为什么我不需要导入推断类型

时间:2016-12-13 21:27:38

标签: scala types casting jvm return-type-deduction

我觉得我应该在此之前加上我用sbt构建项目的事实。

我的问题是,如果在编译时一个方法返回一个无类型的东西,在我调用该方法的文件中,只要我使用类型推断,一切都会编译。一旦我尝试将未导入的类型分配给我使用函数的返回值创建的var / val,我就会遇到编译器错误。

假设我在两个包中有两个类。包App中的课程main和课程Imported中的课程libraries。让我们进一步说,我们在包main中有一个类ImportedFactory,并且该类有一个方法来创建Imported类型的对象。

这段代码编译得很好:

class App() {
    // method return object of type Imported
    val imp = ImportedFactory.createImportedObject() 
}

这不是:

class App() {
    // method return object of type Imported
    val imp : Imported = ImportedFactory.createImportedObject() 
}

这又一次:

import libraries.Imported

class App() {
    // method return object of type Imported
    val imp : Imported = ImportedFactory.createImportedObject() 
}

这似乎是一种相当奇怪的行为。对于编译时带类型推断的语言来说这是正常的吗?由于我的无知,我还没注意到go / C ++中的语言?

两种有效方法中的一种(导入和显式类型与感染)相比有哪些优点/缺点? (当然,期望一个更明确,更冗长,另一个更短)

这是黑魔法还是Scala编译器以相当直接的方式完成这些推论?

2 个答案:

答案 0 :(得分:5)

导入的唯一功能是在当前范围内提供不完全限定的名称。你也可以这样写:

class App() {
    val imp: libraries.Imported = ImportedFactory.createImportedObject() 
}

import libraries.Imported的原因是让您可以编写较短的名称Imported。如果您让编译器推断出类型,则不要在代码中提及类型,因此您不必导入其较短的名称。

顺便说一句:这与C ++中的动态转换无关。代码中唯一可行的机制是类型推断。

答案 1 :(得分:1)

注意:使用术语类型推断

,您将获得更好的搜索结果

使用val imp = ImportedFactory.createImportedObject(),您可以让编译器根据类型推断确定imp应该是什么类型。无论createImportObject返回什么类型,都是imp的类型。

使用val imp : Imported = ImportedFactory.createImportedObject(),您明确声明imp Imported。但编译器不知道你的意思,除非你......导入......它。

这两种方法都有其优点:

推断类型

推断类型非常适用于将类型显而易见的代码放在一起时:

val i = 1 // obviously `i` is an int
val j = i + 10 // obviously still an int

对于当地的vars / vals来说,这种类型的写入也太痛苦了

val myFoo: FancyAbstractThing[TypeParam, AnotherTypeParam[OhNoMoreTypeParams]] = ...
// vs
val myFoo = FancyThingFactory.makeANewOne()

缺点是,如果您允许公共def / val具有推断类型,则确定如何使用该方法可能更加困难。因此,省略类型注释通常仅用于简单常量,而在“客户端代码”不必查看的本地val / vars中。

显式类型

如果你想编写库代码(即public vals / defs),那么惯例就是明确地输入它们。

可能最简单的原因是因为:

def myLibraryMethod = {
  // super complicated implementation
}

更难理解
def myLibraryMethod: String = {
  // super complicated implementation
}

明确键入代码的另一个好处是,当您希望公开一个不太具体的类型而不是实际值时:

val invalidNumbers: Set[Int] = TreeSet(4, 8, 15, 16, 23, 42)

在此示例中,您不希望客户端代码需要关心您的invalidNumbers实际上是TreeSet。这是一个实现细节。在这种情况下,你隐藏了一些信息,这些信息虽然是真的,但会分散注意力。