在Scala(和Java)中,类和类型有什么区别?

2022-08-31 16:59:55

斯卡拉

在Scala中,类和类型之间的差异在哪里可以观察到,为什么这种区别很重要?

它只是从语言设计的角度考虑,还是在编程Scala时具有“实际”影响?

还是它是“确保类型系统边界”的基础(在我看来)?NothingNull

爪哇岛

上面提到的考虑/差异/问题中有多少也可以在Java中识别出来?


(请参阅类型和类之间的区别是什么?作为与语言无关的介绍。


答案 1

当你说“类型”时,我会假设你主要是指静态类型。但我很快就会讨论动态类型。

静态类型是可以静态证明的程序的一部分的属性(静态意味着“不运行它”)。在静态类型语言中,无论您是否编写,每个表达式都有一个类型。例如,在 Cish “int x = a * b + c - d”中,a,b,c,和 d 有类型,a * b 有类型,a * b + c 有类型,a * b + c -d 有类型。但是我们只用类型注释了 x。在其他语言中,例如Scala,C#,Haskell,SML和F#,即使这样也没有必要。

究竟哪些属性是可证明的取决于类型检查器。

另一方面,Scala样式类只是一组对象的规范。该规范包括一些类型信息,并包括许多实现和表示细节,例如方法主体和私有字段等。在 Scala 中,类还指定了一些模块边界。

许多语言有类型但没有类,许多语言有类但没有(静态)类型。

类型和类之间存在一些可观察到的差异。List[String] 是一个类型,但不是一个类。在Scala中,List是类,但通常不是类型(它实际上是一种高级类型)。在C#中,List不是任何类型的类型,在Java中它是一种“原始类型”。

Scala提供结构类型。{def foo : Bar} 表示任何可证明具有返回 Bar 的 foo 方法的对象,而不考虑类。它是一种类型,但不是类。

可以使用类型参数抽象类型。当你写 def foo[T](x : T) = ...时,那么 foo T 的主体内部就是一个类型。但T不是一个类。

类型在Scala中可以是虚拟的(即“抽象类型成员”),但是现在使用Scala的类不能是虚拟的(尽管有一种样板繁重的方式来编码虚拟类 https://wiki.scala-lang.org/display/SIW/VirtualClassesDesign)

现在,动态类型。动态类型是运行时在执行某些操作之前自动检查的对象的属性。在动态类型化的基于类的 OO 语言中,类型和类之间存在很强的相关性。同样的事情也发生在JVM语言上,如Scala和Java,它们具有只能动态检查的操作,例如反射和转换。在这些语言中,“类型擦除”或多或少意味着大多数对象的动态类型与其类相同。或多或少。例如,对于通常不会擦除的数组,则情况并非如此,以便运行时可以区分 Array[Int] 和 Array[String]。但请记住我的广泛定义“动态类型是运行时自动检查的对象的属性”。使用反射时,可以将任何消息发送到任何对象。如果对象支持该消息,那么一切都会解决。因此,谈论所有可以像鸭子一样嘎嘎作响的对象作为动态类型是有道理的,即使它不是一个类。这就是Python和Ruby社区所说的“鸭子类型”的本质。此外,根据我的广义定义,甚至“零度”也是一种动态类型,因为在大多数语言中,运行时会自动检查数字以确保您不会被零除。有非常非常少的语言可以通过使零(或非零)成为静态类型来静态证明这一点。

最后,正如其他人所提到的,像int这样的类型没有类作为实现细节,像Null和Any这样的类型有点特殊,但可以有类而没有,像Nothing这样的类型甚至没有任何值,更不用说类了。


答案 2

好吧,我会咬...詹姆斯有一个很好的答案,所以我将尝试一种不同的机智,并给出一个更脚踏实地的观点。

从广义上讲,类是可以实例化的东西。单例对象(scala)特征(Scala)和接口(Scala)通常也被认为是类。这是有道理的,因为单例仍然是实例化的(通过编译器生成的代码),并且接口可以作为子类的一部分进行实例化。

这就引出了第二点。类是大多数面向对象语言中的主要设计单元(尽管不是像javascript这样基于原型的语言)。多态性和子类化都是根据类来定义的。类还提供命名空间和可见性控件。


类型是一个非常不同的野兽,系统可以表达的每个可能的值都会有一个或多个类型,这些类型有时可以等同于类,例如:

(Int) => String // both the type and class are Function1[Int,String]
"hello world" // class and type are String    

您还可以在Scala和Java之间获得一些有趣的差异:

7 // both the class and type are Int in Scala
  // in Java there's no class and the type is Integer.TYPE

println("hello world") // the return type is Unit, of class Unit
                       // Java has void as a type, but no corresponding class

error("oops") // the type and class are both "Nothing"

以及真正有趣的类型,这些类型根本不是类。例如,始终引用 的唯一类型 。它是单个实例所独有的,甚至与同一类的其他实例不兼容。this.typethis

还有抽象类型和类型参数。例如:

type A // 'A' is an undetermined abstract type
       // to be made concrete in a subclass

class Seq[T] { ... } // T is a type, but not a class

Seq很有趣,因为它是一个类,但不是一个类型。更准确地说,它是一个“类型构造函数”;当提供必要的类型参数时,它将构造一个有效的类型。类型构造函数的另一个术语是“高级类型”,我个人不喜欢这个术语,因为“类型构造函数”鼓励我像任何其他形式的论证一样从提供类型的角度来思考 - 一个对Scala很有帮助的心智模型。

“高等类型”正确地暗示了它有一个“种类”,即,这种表示法表示将采用单个类型并产生单个类型(这类似于用于描述函数的curried表示法)。作为比较,这种类型是因为它需要两个类型参数。Seq* => *SeqMap* => * => *