如果Scala是一种编译语言,那么为什么';它是否事先检测到该程序中的越界异常?

如果Scala是一种编译语言,那么为什么';它是否事先检测到该程序中的越界异常?,scala,interpreted-language,compiled-language,fixed-length-array,Scala,Interpreted Language,Compiled Language,Fixed Length Array,该计划是: object Hello extends App { val a: List[Int] = List(1, 3, 4, 5, 8, 10, 11, 22, 33) for (i <- 0 to 11) println(a(i)) } 它是如何在编译时没有检测到索引将要越界的?编译语言不应该这样做吗?如果没有,请分享编译时检查中包含的内容和未包含的内容好吗 作为一个新手,我总是听说,编译语言非常棒,它们在编译时发现错误,因此更加健壮。

该计划是:

object Hello extends App {
    
    val a: List[Int] = List(1, 3, 4, 5, 8, 10, 11, 22, 33)
    for (i <- 0 to 11)
        println(a(i))

}
它是如何在编译时没有检测到索引将要越界的?编译语言不应该这样做吗?如果没有,请分享编译时检查中包含的内容和未包含的内容好吗


作为一个新手,我总是听说,编译语言非常棒,它们在编译时发现错误,因此更加健壮。

这里的主要问题是,Scala中的
for
与其他语言中的
并不意味着相同。问题中的代码相当于

(0.to(11)).foreach(i => println(a.apply(i))
编译器必须检查许多不同的方法并推断它们的行为,以确定
apply
方法是否会抛出异常

但是编译语言的主要优点是性能,而不是错误检查。强类型语言(通常是编译的)提供更好的错误检测。

您不应该将(或键入的)与类型化语言混淆。不长于
n
元素的集合是依赖类型的典型示例。正在编译的语言意味着除了运行时检查之外还有编译时检查。是在运行时还是在编译时进行特定检查(如检查集合长度)是您的选择(或语言设计器的选择或标准库设计器的选择)。即使一个检查是在编译时进行的,是用类型编码还是用不同的工具编码也是一种选择


仅仅因为编译了某些内容,并不能让它在编译时神奇地检查边界。类型化语言很好地捕捉类型错误,但算术和逻辑错误更难捕捉(如果不是实际上不可能的话)。另一方面,Scala也是一种更具声明性的语言,声明性语言也有助于减少错误。例如,您可以编写一种更具声明性的
a.foreach(println)
,它在运行时不会因错误边界而失败(实际上比
更有效)@是的,这是显而易见的。我的
for
语句通过使用
for将不会出现异常(i@lousycoder声明性语言的要点是,您不需要考虑这些事情,也不需要为简单的细节(如
-1
)修复代码。例如,当您将
map
filter
foldLeft
等内容与它们的命令式对应内容进行比较时,这一点就更加明显了是的,我还不习惯这种声明式风格。从这个意义上说,我不需要关注细节。你能不能在回答中对主要关键词做更多的说明:性能,强类型?性能的提高来自于编译r能够投入大量资源优化代码,这对于解释语言或即时编译语言来说是不可能的。强类型太复杂了,无法在这里讨论,但其他地方有很多关于它的文章!如果一个问题被否决,应该自动删除吗?到底是什么在优化代码?不是苏关于下行投票,我想这是因为问题并不是严格意义上的编程问题。优化有多种形式,但一个很好的例子是循环的自动矢量化,这对于即时编译来说太耗时了,但速度很快。先生,如果我直接把
a(10)
,那么它也会在python等语言中导致错误。当我听说或者我学到的是,在python等解释语言中,代码执行是逐行进行的。而在编译语言中,首先检查代码是否有错误,如果发现干净,则转换为机器语言。因此,在python等语言中,如果迭代时,Option出现在out of bound成员处,这根据上面的书本式定义是有意义的。但是,当这发生在Scala中时,我真的不知道代码是如何执行的。@lousycoder正在编译的语言意味着有两个阶段:编译时和运行时。
IndexOutOfBoundsException
对于您的
列表
问题发生在运行时。我的答案中的
大小的
错误发生在编译时。你现在看到区别了吗?@lousycoder确实在编译过程中检查了你的代码是否有错误。但是它检查了一些错误,而不是所有错误。如果你试图将
列表[String]
而不是预期的
列表[Int]
编译器将捕获此类错误。但如果您的程序计算的是
43
而不是正确的
42
,则编译器很可能不会捕获此类错误。因此,使用编译语言并不意味着您可以避免编写测试来验证程序在运行时的执行情况。@lousycoder您可以转移一些检查从运行时到编译时。比如使用
size
HList
而不是
List
。但这并不总是容易的。原则上,您可以尝试在类型级别对业务逻辑进行编码,然后在编译时甚至可以捕获到
43
42
之类的错误。但仍然存在一些错误(输入输出错误、内存错误、连接错误等)将保留到运行时。先生,感谢您提供了一个清晰的图片。这对我现在来说是有意义的。
(0.to(11)).foreach(i => println(a.apply(i))
import shapeless.Sized
import shapeless.nat._

val a: Sized[List[Int], _9] = Sized[List](1, 3, 4, 5, 8, 10, 11, 22, 33)

a(10) // doesn't compile