2011-01-25 142 views
11

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

当你想将一个庞大的数据结构传递给一个方法,但你不想复制它时,这会很有用。在这种情况下,通过引用调用看起来很完美。

+1

我不认为你可以通过Scala中的值传递数据结构。 – Gabe 2011-01-25 04:46:23

+0

@Gabe它仍然是[传递/调用值](http://en.wikipedia.org/wiki/Evaluation_strategy)(AnyRef类型的传递值 - 底层对象引用)和Python/Java人喜欢滥用“pass-by-reference”这个术语;-)。但是,传递/调用引用意味着在函数*中设置变量*将设置传入变量的值(例如,在C++中使用`&ref`或使用VB中的`ByRef`或使用C#中的`out/ref`) 。这可以通过传递对象和状态变化来模拟*但它不相同(C可以通过修改指针引用的值来模拟它)。 – 2011-01-25 07:04:02

+1

@pst:我指的是“将庞大的数据结构传递给方法”部分。 Scala有一种方法,我不知道在将数据结构传递给函数时复制数据结构,或者数据结构已经通过引用传递,并且来自OP的引用是不相关的。 – Gabe 2011-01-25 16:55:50

回答

34

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

由于您总是通过指向对象的指针而不是对象本身,因此您不必重复复制巨型对象。

顺便提一下,Scala的名称调用是通过值调用来实现的,该值是一个(指向函数的)函数对象,它返回表达式的结果。

0

对于“一切都是对象”并且对象引用无法访问的语言,例如Java和Scala,那么每个函数参数都是在语言之下的某个抽象层次上通过值传递的引用。但是,从语言抽象的语义角度来看,根据函数是否提供了引用对象的副本,可能会有引用调用或值调用。在这种情况下,“共享呼叫”一词既包含在抽象的语言层面上的引用引用和值引用。因此,认为Java是在语言语义之下的抽象层次上进行价值调用是正确的(即,比较它如何被假设转换为C或用于虚拟机的字节码),同时还说Java和Scala(除了内建类型)在其“一切都是对象”抽象的语义上通过引用进行引用。在Java和Scala中,某些内置(a/k/a原语)类型自动获取传值(例如int或Int),并且每个用户定义的类型都是通过引用传递的(即必须手动复制他们只传递他们的价值)。

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

也许维基百科对传递值和按值传递之间的区别感到困惑?我认为按值传递是更通用的术语,因为它适用于赋值表达式以及函数应用程序。我没有费心去尝试在维基百科进行修正,让其他人去散布。

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


投票的人显然不明白“分享呼叫”是什么。

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


即使有纯度,也没有图灵完整的语言(即图灵语言)。允许递归)完全是陈述性的,因为它必须选择一个评估策略。评估策略是功能与参数之间的相对运行时评估顺序。功能的评估策略可以是严格的,也可以是非严格的,因为所有表达式都是函数,所以它们分别与渴望或懒惰相同。 Eager意味着参数表达式在它们的函数之前被评估;而懒惰的意思是参数表达式只在函数首次使用的运行时刻被评估(一次)。 评估策略决定了性能,确定性,调试和操作语义的折衷。对于纯程序,它不会改变指称的语义结果,因为纯粹性,评估顺序的命令性副作用只会导致内存消耗,执行时间,延迟和非终止域的不确定性(即分类限制) 。基本上所有表达式都是(组成)函数,即常量是没有输入的纯函数,一元运算符是一个输入的纯函数,二元运算符是具有两个输入的纯函数,构造函数是函数,甚至控制语句(例如如果,因为,while)可以用函数建模。我们评估这些函数的顺序不是由语法定义的,例如, f(g())可以热切地评估g,然后f对g的结果进行评估,或者它可以评估f,并且只有在f内需要结果时才懒惰地评估g。

前者(渴望)是按值(CBV),后者(懒惰)是按名称(CBN)。 CBV具有不同的基于共享的调用,这在现代OOP语言(如Java,Python,Ruby等)中很流行,其中不纯的函数通过引用隐式输入一些可变对象。 CBN有一个不同的需求调用(也称为CBN),其中函数参数只进行一次评估(与记忆函数不同)。按需呼叫几乎总是用来代替按名称呼叫,因为它的指数速度更快。由于所声明的功能层次与运行时评估顺序之间的不一致,通常CBN的两种变体都仅以纯度出现。

语言通常有一个默认的评估策略,有些语法可以选择强制函数在非默认情况下评估。由于第二个操作数不是默认值,所以通常会评估布尔连接(a/k/a“和”,& &)和分离(a/k/a“或”,||)运算符,因为第二个操作数不是需要一半的情况下,即真||任何东西== true和false & & anything == false。

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中很少。好处在于,这使得调用者可以更灵活地处理发送给参数的值。例如。

someFunc((x => println(x))) 
相关问题