Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-core/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 部分应用程序和返回函数之间有区别吗?_Scala_Currying_Partial Application - Fatal编程技术网

Scala 部分应用程序和返回函数之间有区别吗?

Scala 部分应用程序和返回函数之间有区别吗?,scala,currying,partial-application,Scala,Currying,Partial Application,就底层而言:堆栈/堆分配、垃圾收集、资源和性能,以下三者之间的区别是什么: def Do1(a:String) = { (b:String) => { println(a,b) }} def Do2(a:String)(b:String) = { println(a,b) } def Do3(a:String, b:String) = { println(a,b) } Do1("a")("b") Do2("a")("b") (Do3("a", _:String))("b") 除了声明中

就底层而言:堆栈/堆分配、垃圾收集、资源和性能,以下三者之间的区别是什么:

def Do1(a:String) = { (b:String) => { println(a,b) }}
def Do2(a:String)(b:String) = { println(a,b) }
def Do3(a:String, b:String) = { println(a,b) }

Do1("a")("b")
Do2("a")("b")
(Do3("a", _:String))("b")

除了声明中关于每个类接受和返回多少参数的明显表面差异之外,反编译下面的类(注意与您的问题相比,对
Do2
的额外调用):

生成以下纯Java代码:

public class Test {
    public Function1<String, BoxedUnit> Do1(final String a) {
        new AbstractFunction1() {
            public final void apply(String b) {
                Predef..MODULE$.println(new Tuple2(a, b));
            }
        };
    }

    public void Do2(String a, String b) {
        Predef..MODULE$.println(new Tuple2(a, b));
    }

    public void Do3(String a, String b) {
        Predef..MODULE$.println(new Tuple2(a, b));
    }

    public Test() {
        Do1("a").apply("b");
        Do2("a", "b");
        new AbstractFunction1() {
            public final void apply(String b) {
                Test.this.Do2("a", b);
            }
        }.apply("b");
        new AbstractFunction1() {
            public final void apply(String x$1) {
                Test.this.Do3("a", x$1);
            }
        }.apply("b");
    }
}
Do2
Do3
向下编译为相同的字节码。区别只存在于
@ScalaSignature
注释中


Do1
是直截了当的:立即应用返回的函数

Do2("a")("b")

Do2("a", "b");
使用
Do2
,编译器发现这不是部分应用程序,并将其编译为单个方法调用


这里,首先部分应用
Do2
Do3
,然后立即应用返回的函数

Do2("a")("b")

Do2("a", "b");

结论:

我想说,
Do2
Do3
在生成的字节码中基本上是等价的。一个完整的应用程序产生一个简单、廉价的方法调用。部分应用程序在调用方生成匿名函数类。您使用的变体主要取决于您试图传达的意图


Do1
始终创建立即函数对象,但在被调用的代码中这样做。如果您希望大量执行函数的部分应用程序,那么使用此变量将减少代码大小,并且可能会更早地触发JIT编译器,因为调用同一代码的频率更高。完整的应用程序将更慢,至少在JIT编译器内联之前,并且随后在各个调用站点消除对象创建。我不是这方面的专家,所以我不知道你是否可以期待这种优化。我最好的猜测是,对于纯函数,您可以这样做。

好吧,这与咖喱无关。无论如何,这个问题是关于秘密的。对不起,我忽略了你问题的一个重要部分:它与内存分配的关系。我仍然认为相关问题中有很多相关信息,但这不是重复的,你是对的。我猜在字节码级别上,
Do2
Do3
是相同的。您对
Do2
的调用可能是一个简单的方法调用,而我希望
Do3
调用创建一个中间函数对象
Do1无论如何都应该这样做。也许现在有更多时间的人可以做一个
javap
并写下来作为答案。非常感谢您的详细分析,尤其是结论。感谢您的时间和努力。@Alex不客气!再次抱歉,你一开始没抓住问题的重点。回答这个问题很有趣!
def Do2(a: String)(b: String) = { println(a, b) }

public void Do2(String a, String b) {
    Predef.MODULE$.println(new Tuple2(a, b));
}

def Do3(a: String, b: String) = { println(a, b) }

public void Do3(String a, String b) {
    Predef.MODULE$.println(new Tuple2(a, b));
}
Do1("a")("b")

Do1("a").apply("b");
Do2("a")("b")

Do2("a", "b");
(Do2("a") _)("b")

new AbstractFunction1() {
    public final void apply(String b) {
        Test.this.Do2("a", b);
    }
}.apply("b");

(Do3("a", _: String))("b")

new AbstractFunction1() {
    public final void apply(String x$1) {
        Test.this.Do3("a", x$1);
    }
}.apply("b");