可以通过引用来调用Scala吗?

时间:2011-01-25 04:39:45

标签: scala calling-convention evaluation-strategy

我知道Scala支持ALGOL的call-by-name,我想我明白这意味着什么,但是Scala能像C#,VB.NET和C ++那样通过引用进行调用吗?我知道Java不能通过引用进行调用,但我不确定这种限制是否仅仅是由于语言还是JVM。

当您想要将大量数据结构传递给方法但是您不想复制它时,这将非常有用。在这种情况下,按引用调用似乎很完美。

4 个答案:

答案 0 :(得分:42)

Java和Scala都只使用值调用,除了该值是基元或指向对象的指针。如果你的对象包含可变字段,那么这个和通过引用调用之间几乎没有实质性的区别。

由于您总是将指针传递给对象而不是对象本身,因此您不必重复复制巨型对象。

顺便提一下,Scala的名字调用是使用call by value实现的,值是一个(指向a的)指针,它返回表达式的结果。

答案 1 :(得分:0)

对于“一切都是对象”并且无法访问对象引用的语言,例如Java和Scala,然后每个函数参数都是在语言下面的某个抽象级别上传递的值的引用。但是,从语言抽象的语义的角度来看,有一个引用调用或值调用,这取决于函数是否提供了引用对象的副本。在这种情况下,术语“逐个共享”包含抽象语言级别的引用调用和值调用。因此,正确地说,Java在语言语义之下的抽象层次上是按值调用的(即与假设地将其转换为C或虚拟机的字节码中的方式进行比较),同时也说Java和Scala是(内置类型除外)在其“一切都是对象”抽象的语义上的引用调用。

在Java和Scala中,某些内置(a / k / a primitive)类型会自动传递值(例如int或Int),并且每个用户定义的类型都是通过引用传递的(即必须手动复制它们)只传递他们的价值。)

注意我更新了维基百科的Call-by-sharing section以使其更加清晰。

或许维基百科对传值和按值调用之间的区别感到困惑?我认为pass-by-value是更通用的术语,因为它适用于赋值表达式以及函数应用程序。我没有费心去尝试在维基百科上做出这样的修正,留给其他人讨论。

当对象是不可变的时,在“引用调用”和“按值调用”之间“一切都是对象”的语义级别没有区别。因此,可以通过延迟按值复制直到修改对象来优化允许声明按值调用与按引用调用(例如我正在开发的类似Scala语言)的语言。


投票决定这一点的人显然不明白“分享号召”是什么。

下面我将添加我为我的Copute语言(针对JVM)所做的写作,在那里我讨论评估策略。


即使有纯度,也没有图灵完整语言(即允许递归)完全是声明性的,因为它必须选择评估策略。评估策略是函数及其参数之间的相对运行时评估顺序。函数的评估策略可以是严格的也可以是非严格的,分别与渴望或懒惰相同,因为所有表达式都是函数。 Eager意味着参数表达式在它们的函数之前被计算;而懒惰意味着参数表达式仅在它们首次在函数中使用的运行时刻被评估(一次)。 评估策略确定性能,确定性,调试和操作语义权衡。对于纯程序,它不会改变指称语义结果,因为纯度,评估顺序的命令性副作用只会导致内存消耗,执行时间,延迟和非终止域的不确定性(即,明确限制)

基本上所有表达式都是(组合)函数,即常量是没有输入的纯函数,一元运算符是带有一个输入的纯函数,二元运算符是带两个输入的纯函数,构造函数是函数,甚至是控制语句(例如,如果,for,while)可以用函数建模。我们评估这些函数的顺序不是由语法定义的,例如f(g())可以急切地评估g然后对g的结果进行评估,或者它可以评估f并且只有在f内需要其结果时才懒惰地评估g。

前者(渴望)是按值调用(CBV),后者(懒惰)是按名称调用(CBN)。 CBV有一个变体call-by-sharing,它在现代的OOP语言中很流行,例如Java,Python,Ruby等,其中不纯函数通过引用隐式输入一些可变对象。 CBN有一个变量按需调用(也就是CBN),其中函数参数只被评估一次(与memoizing函数不同)。几乎总是使用按需调用而不是按名称调用,因为它以指数方式更快。通常,CBN的两个变体仅出现纯度,因为声明的函数层次结构与运行时评估顺序之间存在不一致。

语言通常具有默认评估策略,并且一些语言具有可选地强制在非默认值中评估函数的语法。默认情况下急于求助的语言通常会懒惰地评估布尔连接(a / k / a“和”,&&)和析取(a / k / a“或”,||)运算符,因为第二个操作数不是在一半的情况下需要,即真实的||任何东西== true和false&&任何事情== false。

答案 2 :(得分:0)

以下是如何在Scala中模拟参考参数。

def someFunc( var_par_x : Function[Int,Unit] ) {
    var_par_x( 42 ) // set the reference parameter to 42
}

var y = 0 
someFunc( (x => y=x) )
println(y)

嗯,好吧,不完全是Pascal或C ++程序员习惯的;但是,在Scala中很少。好处是,这使得调用者可以更灵活地使用发送给参数的值。 E.g。

someFunc( (x => println(x) ) )

答案 3 :(得分:0)

我正在阅读有关此主题的内容,并且看到了这些问题和答案。 我想到了这个示例,如果您将其复制并粘贴到文本文件中,然后将其保存为* .bat,如testref.bat:)

,则该示例实际上有效
public class MyInputModel
{
    [StringLength(maximumLength: 4000)]
    public string Description { get; set; }

    [Required]
    public IFormFile Icon { get; set; }
}

我只想确认这是否真的是通过引用调用变量的方法?