2016-07-20 11 views
2

は、以下のコードを検討:R tryCatchブロック内の可変スコープ:tryCatchより前に定義されたローカル変数を変更するには<<が必要ですか?

test1 <- "a" 
test2 <- "a" 
tryCatch(stop(), error= function(err){ 
    print(test1) 
    print(test2) 
    test1 <- "b" 
    test2 <<- "b" 
}) 

結果:

print(test1) 
[1] "a" 
print(test2) 
[1] "b" 

変数TEST1の値がtryCatchブロック内で可視であるが、とそれを変更する「< - 」演算子は、外部の値に影響を及ぼしませんtryCatchブロック

新しい値が< <で割り当てられている場合は、その効果があります。どうして?

tryブロックブロック内の< < - 演算子を使用して、このブロック外のローカル変数の値を変更することをお勧めしますか?予想外の副作用がありますか?

EDIT:Bernhardの回答に基づいて、この問題に対する正しいアプローチを次のコードで補完していますか?

test1 <- "a" 
test2 <- "a" 
new_values<-tryCatch(
    { 
    print("hello") 
    stop() 
    } 
, error= function(err){ 
    # I want to change the test1 and test 2 variables to "b" only if error occurred. 
    test1 <- "b" 
    test2 <- "b" 
    return(list(test1=test1,test2=test2)) 
}) 
if (is.list(new_values)) 
{ 
    test1<-new_values$test1 
    test2<-new_values$test2 
} 

結果:

> print(test1) 
[1] "b" 
> print(test2) 
[1] "b" 
+0

技術的には、エラー状態が発生したときに呼び出される無名関数です。すべての伝統的な[スコープ規則](http://adv-r.had.co.nz/Functions.html#lexical-scoping)が適用されます。 '<< - 'には注意が払われていますが、それは賢明に使われるためにRによって提供されるツールです。パッケージを書くときにはしばしば必要となり、通常の分析/スクリプトではコメントやコメントを避ける必要があります。 – hrbrmstr

答えて

1

「< <は - 」それは決して、または場合にのみ、メモリや高速力あなたがそうするようにR.利用に属さない副作用のために作られています。ブロックは、それ自身のスコープを持っており、あなたがそのタスクのリターンは()があることを、「外」environementにブロック内のデータを与えたい場合:

test2 <- "a" 

test2 <- tryCatch(stop(), error= function(err){ 
    somevariable <- "b" 
    return(somevariable) 
}) 

これは、すべての人にそれを明確にそのトップレベルになりますtest2が "a"に設定され、その最上位のtest2が別のものに設定されます。 '< < - 'これは簡単に起こり、いくつかの関数はtoplevel test2を変更し、誰かが不思議に思う、なぜtoplevel test2が全く変更されたのか。ただしないでください< < - 。

複数の結果を返す必要がある場合は、結果のリストまたはオブジェクトを返します。

EDIT:OPは、現在のブロックだけでなく現在の関数も終了するので、return文に注意する必要があることを指摘しています。考えられる解決策は、単純なブロックの代わりに関数で計算を実行することです。次の例は、これを説明する必要があります。

safediv <- function(a, b){ 
    normalDo <- function(a, b){ 
     return(list(value=a/b, message=NULL)) 
    } 
    exceptionalDo <- function(err){ 
     return(list(value=NaN, message="caught an error! Change global variable?")) 
    } 
    results <- tryCatch(normalDo(a, b), error=exceptionalDo) 
    print("safediv is still running after the returns within the functions.") 
    return(results) 
} 

# try it out 
safediv(5, 3) 
safediv(5, 0) 
safediv(5, "a") 
+0

この解決策に関して私には明らかなことはありません。たとえば、tryCatchブロックのボディにprint()出力があり、エラーが発生しなかった場合、test2変数に返されます。エラーが発生した場合、test2変数の値はエラー関数によって設定されます。したがって、 "外部"はtest2変数を何らかの形で解析してエラーが発生していないかどうかを判別し、破棄可能な印刷出力のコピーを含んでいるか、またはエラーが発生しており、この変更を「外部」変数に伝播する必要があります。 – tomas

+0

あなたのアドバイスと以前のコメントに基づいて、完全な解決策を試して私の質問を編集しました。あなたの意見は正しいですか? – tomas

+0

これは正しく見えます。私はおそらく 'if(is。list(..)) 'の部分を返し、どちらの場合でも適切な値のリストを返しますが、これは私だけかもしれません。 – Bernhard

関連する問題