16

私はon.exitRの機能を知っています。これは素晴らしいことです。通常またはエラーの結果として、呼び出し元の関数が終了すると、式が実行されます。

私が望むのは、呼び出し元の関数が正常に戻った場合にのみ式が実行され、エラーの場合には実行されないことです。関数が正常に戻る可能性のある複数のポイントと、失敗する可能性のある複数のポイントがあります。これを行う方法はありますか?

myfunction = function() {
     ...
     on.exit( if (just exited normally without error) <something> )
     ...
     if (...) then return( point 1 )
     ...
     if (...) then return( point 2 )
     ...
     if (...) then return( point 3 )
     ...
     return ( point 4 )
}
4

3 に答える 3

14

の全体のポイントはon.exit()、終了ステータスに関係なく正確に実行されます。したがって、エラー信号は無視されます。これはfinally、tryCatch関数のステートメントと同等のafaikです。

通常の終了時にのみコードを実行する場合は、コードの最後に配置するだけです。elseはい、ステートメントを使用し、出口点を1つだけ作成して、少し再構築する必要がありますが、それは一部の人にとっては優れたコーディング手法と見なされています。

あなたの例を使用すると、それは次のようになります。

myfunction = function() {
     ...
     if (...) then out <- point 1 
     ...
     else if (...) then out <- point 2 
     ...
     else if (...) then out <- point 3 
     ...
     else out <-  point 4 

     WhateverNeedsToRunBeforeReturning

     return(out)
}

または、を使用したこのアイデアの優れた実装については、Charlesの回答をlocal()参照してください。

の使用を主張する場合on.exit()は、トレースバックメカニズムの動作を賭けて次のようなことを行うことができます。

test <- function(x){
  x + 12
}                               

myFun <- function(y){
    on.exit({

        err <- if( exists(".Traceback")){
           nt <- length(.Traceback)        
           .Traceback[[nt]] == sys.calls()[[1]]
        } else {FALSE}

        if(!err) print("test")
    })  
    test(y)
}

.Tracebackエラーが発生した最後の呼び出しスタックが含まれています。そのスタックの一番上の呼び出しが現在の呼び出しと等しいかどうかを確認する必要があります。その場合、呼び出しが最後のエラーをスローした可能性が非常に高くなります。したがって、その条件に基づいて、私が決して使用しないソリューションを自分でハックすることを試みることができます。

于 2012-11-28T11:00:55.967 に答える
8

すべてのリターン関数呼び出しの引数を、実行したいコードでラップするだけです。したがって、あなたの例は次のようになります。

foo = function(thing){do something; return(thing)}
myfunction = function() {
     ...
     if (...) then return( foo(point 1) )
     ...
     if (...) then return( foo(point 2) )
     ...
     if (...) then return( foo(point 3) )
     ...
     return ( foo(point 4) )
}

または、各then節を 2 つのステートメントにします。いくつかのコードをさまざまな場所に利用するために使用on.exitすると、不気味な遠隔操作の問題が発生し、赤ん坊の Dijkstra が泣くようになります (Dijkstra の「GOTO は有害と見なされる」論文を参照してください)。

于 2012-11-28T14:03:05.527 に答える
6

@ Jorisの回答に対する私のコメントのもう少し読みやすいバージョン:

f = function() {
  ret = local({
    myvar = 42
    if (runif(1) < 0.5)
      return(2)
    stop('oh noes')
  }, environment())
  # code to run on success...
  print(sprintf('myvar is %d', myvar))
  ret
}
于 2012-11-28T14:27:48.263 に答える