【问题标题】:How to return from the function which called the current function?如何从调用当前函数的函数返回?
【发布时间】:2020-04-17 17:19:08
【问题描述】:

假设,我有两个函数 f1()f2()。为了达到其目的,f1() 需要返回一个真实值。 f1() 调用 f2() 并根据条件,我希望 f2() 返回一个真实值或直接从 f1()(调用函数)返回。

//f1()
function f1() {
    const a = f2();
    ...
    ...
    return ...
}

//f2()
function f2() {
    ...
    if(error) {
        // I want to execute return on f1()'s scope here
    }
    ...
    return ...
}

我的方法:

//f2()
function f2(callback: () => void) {
    ...
    if(error) {
        callback();
    }
    ...
    return ...
}

//f1()
function f1() {
    const a = f2(() => {return...});
    ...
    ...
    return ...
}

不幸的是,它只会按预期返回 f2() 中的值。

如何解决这个问题?请不要建议其他事情,例如在 if 块中从 f2() 返回 null 并根据条件在 f1() 中返回。由于我自己的原因,我希望f2() 结束对f1() 的执行。

谢谢。

【问题讨论】:

    标签: typescript


    【解决方案1】:

    f2 不一定知道它是从f1 调用的,对吧?有一天你可以重构让f1 调用f3,然后调用f2。那时还不清楚您是否希望f2 强制返回f3f1。一般来说,语言期望f2written not to know exactly where it is being called,或者对调用方法中发生的事情有深入的控制:f2 的返回值应该替代对f2 的调用,而无需进一步控制@987654337 @的执行。

    解决这个问题的典型方法是throw 一个异常(它会在堆栈中向上到它被捕获的点,并且考虑到这似乎是一个错误情况,这将是特别合理的)或@987654339 @ 一个标记值,表示您应该早点返回。听起来像 falsenull 这样的虚假值是不错的选择,但您已经表明这种标准方法不适合您的需求。

    但是,您可以使用的另一种技术是continuation passing style,我建议您这样做,因为您似乎可以编辑f2 以进行回调(其中的延续是special form)。这允许f1 将控制权委托给f2,除了它在成功而不是失败时调用回调。这在 Promises 等异步情况下比在同步情况下更常见,但它可能允许您在同步情况下所需的灵活性,并且如果f2 变为异步,它确实允许您延迟continuation 的调用。它还允许f1 选择是否立即返回,并允许假设的重构f3 接受并传递f1 的延续或传递它自己的延续(可能在之后调用f1 的延续进一步处理)。

    function f1() {
      return f2(a => {
        /* the rest of f1 that consumes a */
        return ...
      });
    }
    
    function f2(continuation: (a: TypeOfA) => typeOfF1) {
      if (error) {
        // f1 returns this immediately, and never has its continuation called.
        return ERROR_VALUE;
      }
      // calculate return value
      return continuation(a);
    }
    

    【讨论】:

    • 尾调用优化的讨论不会涵盖这个吗?例如:stackoverflow.com/questions/310974/…
    • @ThomasBitonti Tail 调用优化描述了如何在不溢出堆栈的情况下很好地实现这个结构,当然,但我没有感觉到这个特定问题足够递归以要求它。我故意忽略了性能问题,因为it's complicated in Javascript right now 并且因为我们在这里只讨论控制流的哲学。
    • 目标似乎是,在调用序列f0 调用f1 调用f2 中,让f2 返回到f0,绕过从f1 的返回。这不就是尾调用优化的基本思路吗?
    • @ThomasBitonti 没有,也没有。首先,目标不仅仅是让f2返回f0,而是f2取消了f1的其余部分,这也暗示了对f2的调用不是在f1 的尾部位置(否则不会有任何取消行为)。其次,尾调用优化不是绕过行为,它只是一个实现细节,可以更好地让您假装计算机具有无限内存,通过说“如果f1 唯一剩下要做的事情是返回此 f2 结果,让我们通过忘记对 f1 的调用来节省内存。如果 f1 有任何事情要做,那就不是 TCO。
    猜你喜欢
    • 1970-01-01
    • 2021-10-23
    • 1970-01-01
    • 2021-01-17
    • 1970-01-01
    • 2018-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多