无论在编译语言中键入(静态还是动态),编译期间不是都会捕获所有错误吗?

Aren't all errors caught during compilation regardless of typing (static vs. dynamic) in a compiled language?

下面是一个answer explaining Dynamic vs. Static Typing.

我很困惑为什么这演示了动态类型和静态类型,因为我认为编译语言的所有错误无论如何都会在编译过程中被捕获,所以它是静态类型还是动态类型都没有关系。

也许这表明静态类型语言总是在 运行 之前引发错误,而动态类型总是在执行期间引发错误,无论它是编译还是解释?

有人可以更深入地解释一下吗?

Here is an example contrasting how Python (dynamically typed) and Go (statically typed) handle a type error:

def silly(a):
    if a > 0:
        print 'Hi'
    else:
        print 5 + '3'

Python does type checking at run time, and therefore:

silly(2)

Runs perfectly fine, and produces the expected output Hi. Error is only raised if the problematic line is hit:

silly(-1) 

Produces

TypeError: unsupported operand type(s) for +: 'int' and 'str'

因为实际执行了相关行

另一方面,Go 在编译时进行类型检查:

package main

import ("fmt"
)

func silly(a int) {
  if (a > 0) {
      fmt.Println("Hi")
  } else {
      fmt.Println("3" + 5)
  }
}

func main() {
  silly(2)
} 

以上编译不通过,报错如下:

invalid operation: "3" + 5 (mismatched types string and int)

编译<->解释量表与动态<->静态类型量表完全正交。 (可能还有另一个编译时类型检查和运行时间类型检查的正交尺度)

例如,您可以使用 Cython 将示例中的 Python 脚本编译为本机二进制文件。它将以完全相同的方式工作,但它将被编译。 Python 脚本也可以使用 mypy 提前进行类型检查,并使用 CPython 进行 运行,它提供 运行 时间类型异常。

另一方面,您可以安装一种具有静态类型和交互式 shell(解释器)的语言,并在代码执行之前尝试类似的表达式 - you'll get a type error。这部分有点令人困惑,因为要得到类型错误,你需要在某种程度上编译代码(处理成 AST 并进行类型检查),但我认为它不符合 "compiled" 的常见定义。

总而言之,您可以进行动态类型编译、静态编译、动态类型解释和静态类型解释。 (repl 中的链接示例可以说是关于强类型的——请随时提供更好的类型)

没有。除非语言是静态类型的,否则编译时不会捕获类型错误。

请注意,无论键入什么,编译都会捕获语法错误


这个例子令人困惑,因为它将 "Static & Compiled" 与 "Dynamic & Interpreted" 结合在一起,这掩盖了不同类型系统的影响。

  • Go 示例如果是 动态类型 就不会抛出错误,尽管已编译!
  • Python 示例如果是 静态类型 将抛出错误,即使该行永远不会被解释!

类型检查与正在编译或解释的语言无关!


我将复习基本概念,然后深入研究示例。


编译与解释

"When source code is translated"

  • 源代码:原始代码(通常由人输入计算机)
  • 翻译:将源代码转换为计算机可以读取的内容(即机器代码)
  • 运行-Time:程序执行命令的时间段(编译后,如果编译)
  • 编译语言:在运行-时间
  • 之前翻译的代码
  • 解释型语言:代码在执行期间即时翻译

正在打字

"When types are checked"

5 + '3' 强类型 语言(例如 Go 和 Python)中类型错误的示例,因为它们不允许 "type coercion" -> 值在特定上下文中更改类型的能力,例如合并两种类型。 弱类型 语言,例如 JavaScript,不会抛出类型错误(导致 '53')。

  • 静态:运行-时间
  • 之前检查的类型
  • 动态:在执行期间即时检查类型

"Static & Compiled" 和 "Dynamic & Interpreted" 的定义非常相似...但请记住它是 "when types are checked" 与 "when source code is translated"。

无论语言是编译型还是解释型,您都会遇到相同类型的错误!您需要在概念上区分这些术语。


Python 例子

动态,​​解释

def silly(a):
    if a > 0:
        print 'Hi'
    else:
        print 5 + '3'

silly(2)

因为 Python 是解释型和动态类型型的,它只翻译和类型检查它正在执行的代码。 else 块永远不会执行,所以 5 + '3' 甚至都不会被查看!

如果是静态类型呢?

甚至在代码 运行 之前就会抛出类型错误。即使它被解释,它仍然在 运行 时间之前执行类型检查。

编译出来了怎么办?

else 块在 运行 之前会是 translated/looked,但因为它是动态类型的,所以不会抛出错误!动态类型语言在执行之前不检查类型,并且该行永远不会执行。


Go 示例

静态,已编译

package main

import ("fmt"
)

func silly(a int) {
  if (a > 0) {
      fmt.Println("Hi")
  } else {
      fmt.Println("3" + 5)
  }
}

func main() {
  silly(2)
}

在 运行ning(静态)之前检查类型并立即捕获类型错误!如果对类型进行解释,仍会在 运行 时间之前检查类型,结果相同。如果它是动态的,即使在编译期间会查看代码,它也不会抛出任何错误。


性能

如果编译语言是静态类型的(相对于动态类型),它在 运行 时会有更好的性能;类型知识允许机器代码优化。

静态类型语言在 运行 时间本质上具有更好的性能,因为在执行时不需要动态检查类型(它在 运行ning 之前检查)。

同样,编译语言在 运行 时速度更快,因为代码已经被翻译,而不需要即时 "interpret"/翻译它。

请注意,编译语言和静态类型语言在翻译和类型检查之前 运行 会有延迟。


更多差异

静态类型会及早捕获错误,而不是在执行过程中发现它们(对长程序特别有用)。它更 "strict" 因为它不允许程序中任何地方出现类型错误,并且通常会阻止变量更改类型,从而进一步防止意外错误。

num = 2
num = '3' // ERROR

动态类型更灵活,有些人对此表示赞赏。它通常允许变量更改类型,这可能会导致意外错误。