Google、"Go"言語の多値を返し計算書に代わる例外?
-
13-09-2019 - |
質問
ていて思ったのはGoogleの代替案の例外を除いて
- :多値を返し"戻val,err;"
- GO,C++:ゼロチェック(早帰り)
- GO,C++:"対応の気エラー"(私の期)
C++:assert(発現)
:defer/パニック/回復している言語機能を追加後、この質問を依頼した
マルチ値を返し有用などの代替?なぜ"を主張"の代替品と?GoogleのようO.K.場合にプログラムを停止エラーが発生した場合にはその取扱いを行わない分けは適切でしょうか。
つくのは珍しい特徴がある関数とメソッド復帰できる複数の値です。でもモザイクをかけることができ改善の武骨なイディオムにCプログラム:in-バンドエラーを返します(など-1EOF)および改変を引数に使います。
Cで書き込みエラーがシグナルによる 負の数のエラーコード 分泌され離れ変動しやすい立地です。に、書きを返し回数と エラー:"あなたが書いたもので一部のバイトが 全てではないですができ、 デバイスである。の署名*ファイルです。書 パッケージos:
func (file *File) Write(b []byte) (n int, err Error)
としての文書は、 バイト数を返します書 非ゼロエラーの場合n!= len(b)この共通のスタイルのを参照 部にエラー処理のためのより 例です。
に返した結果、"パラメータ"の Go機能できる名前 使用して通常変数のように、 の受信パラメータ。場の名の通り、 彼に初期化され、ゼロ 値型の場合の 機能開始この機能は 行を返し計算書のない 引数の現在値を 結果のパラメータとして使用されている 返される値です。
の名義務づけられていませんか でコードが短く、より鮮明:います。した場合は名称 結果nextIntなり明らか る返されるintです。
func nextInt(b []byte, pos int) (value, nextPos int) {
が名前の結果は初期化され、いくつかの、 川に挟まれた島に戻っきの簡素化として として解明.こちらのバージョン io.ReadFullそれを用いたもの:
func ReadFull(r Reader, buf []byte) (n int, err os.Error) {
for len(buf) > 0 && err == nil {
var nr int;
nr, err = r.Read(buf);
n += nr;
buf = buf[nr:len(buf)];
}
return;
}
例外は同様です。多数のデザイン例外が提案されてきたそれぞれ追加し大幅な複雑さの言語とする。も例外をスパンの機能にもgoroutines;て幅広い意味を持つ。懸念も大きな影響があるというのが書けます。その定義より、例外的な経験を他の言語に対応したシミュレーションを行っても大きなインパクトを与える図書館のインタフェースの仕様でができると思うのですが見つデザインすることで真に例外的な励みに共通のエラーへの特別制御の流れを必要とする各プログラマを賠償する一
のようなジェネリック医薬品、例外は開放の問題です。
決定:
自分の顔を 例外を上回るコスト 特に新規プロジェクト.しかし、 既存コードの導入 例外がどう影響するかについて 依存のコードです。場合は例外ができ 伝播を超えて新たなプロジェクトでは、 まな問題を統合 この新プロジェクトを既存の exception-無料のコードです。多く 既存のC++コードをGoogleではない 対応例外で は比較的困難を採用 新しいコードを生成する例外をスローしました。
このGoogleの既存コード ない例外性、コストの を使用した例外はやや振れの大きい 以上のコストに、新しいプロジェクトの変換プロセスが遅い エラーが発生しやすい.るとは考えていないこと の に関する選択肢を 例外などのエラーコードおよび 主張 導入の大幅な 負担となります。
アドバイスを使用例は ないことが前提と哲学的又は 道徳の理由で実践した。このように利用 オープンソースプロジェクトでGoogleと 難しい場合 事業利用の例外を除い の助言に対し例外Google オープンソースプロジェクトです。いもの ろうが異なる場しました いしたら再びゼロから立ち上げました。
猶予算を考える閉会の各ファイルを直後の開館することを保証するグループ人数に関わらず、返却諸表の機能は、ファイルは定休日とさせていただきます。
行動の繰り延べ述のどれかに当てはまるわかりやすく予測可能であある単純なルール:
1.繰延関数の引数が評価の繰り延べの声を評価します。
この例では、表現の"i"の評価がPrintln呼び出しが繰り延べられます。の繰延呼び出し印刷"0"以降の機能に戻ります。
func a() { i := 0 defer fmt.Println(i) i++ return }
2.繰延機能の実行に最初に出したかどうか確認するには、周囲の機能に戻ります。 この機能版画"3210":
func b() { for i := 0; i < 4; i++ { defer fmt.Print(i) } }
3.繰延機能があり、割り当てを返す関数の戻り値です。
この例では、繰延機能を単位とする返り値の後は、周囲の機能に戻ります。このように、この機能は2を返す:
func c() (i int) { defer func() { i++ }() return 1 }
この便利な変更をエラー関数の戻り値;また例えば、視野に入ってまいりました。
パニックが内蔵機能を止める通常のフロー制御を開始騒. 場合に関数Fと呼パニックに、執行の停止、繰延機能をFで実行され、通常、Fを返します、その呼び出し側に返します。呼び出し側に、F次のように動作すの呼び出しを混乱に陥れたのである。にももっと世界に目を向けてのスタックまで全ての機能を現在のgoroutineて返された時点をもって、プログラムがクラッシュします。Panicsができるようになりパニックメソッドを呼び出す。ることもできるように、実行時エラーなど、out-of-bounds配列からです。
回収が可能であることを取り戻し制御の訓goroutine. 回復するだけで使用中の繰延。通常の実行、回復はnilを返し、他にはない。現在のgoroutineが騒ぐ呼び出すと、 回復を獲得価値に与えたパニックおよび通常の実行.
以下に例を示しますプログラムとしての力学パニックになり、先送り:
<snip>
実世界に例のパニックになり、回復のjsonパッケージの標準図書館があります。で復号化すJSON-符号化されたデータセットを再帰的で機能する。が不正なJSONが検出された、パーサに通話パニックでおくつろぎのスタックのトップレベルの関数呼び出しは、回復のパニックを返します適切なエラー値の'エラー'と'unmarshalな機能デコード.go).ある類似の事例この技術のルーチンをコンパイルの正規表現のパッケージです。この条約の図書館である場合でも、パッケージを使パニックには内部に外部APIも提明示的なエラー戻り値です。
その他の用途の繰り延べ以外のファイルです。Close()例と、それ以前を含む)を発表ミューテックス:
mu.Lock() defer mu.Unlock
解決
複数のリターンは行くために固有のものではない、と彼らは例外に代わるものではありませんね。 C(またはC ++)に関しては、それらは複数の値を含む構造体(オブジェクト)を返すための簡潔かつユーザーフレンドリーな代替である。
それはあなたが意味するすべてだ場合は、彼らは、エラーを示すための便利な手段を提供します。
なぜ選択肢と考え、 "アサート" されますか?
デバッグのために最初はアサート。彼らはそれが「不可能」状態、デザインが起こる、とにかく持っているべきではないと言う1である状況でプログラムを停止します。エラーを返すことくらい手助けすることはほとんどありません。コードベースは明らかにまだ動作しませんので、どのように地球上で、それが正常に回復することができますか?注意が必要なバグがあるとき、なぜあなたも、それはするのでしょうか。
の使用は、生産コードでアサート別の問題のビットされて - 明らかにあった性能とコードサイズの懸念があるので、通常のアプローチは、あなたのコード分析とテスト後にそれらを削除することで、「不可能」な状況が実際にあることを確信しています不可能な。破損:あなたは、それ自体を監査だということ、パラノイアのこのレベルでコードを実行している場合しかし、あなたはまた、おそらくあなたはそれが「不可能」な状態で実行している上で実行させた場合、それは危険なほど壊れて何かをするかもしれないことを妄想しています貴重なデータ、スタック割り当てをオーバーランし、おそらくセキュリティの脆弱性を作成します。だから、もう一度、あなただけできるだけ早くシャットダウンしたい。
C ++やJavaなどのプログラミング言語は「不可能」の状況(logic_error
、ArrayOutOfBoundsException
)の例外を提供する場合、彼らが意図せずに考えるようにいくつかのプログラマを奨励:あなたが使うものは、あなたがのために例外を使用のものと同じではありません、本当にためにアサートそのプログラムは、をすることを本当に彼らが制御不能にしている状況から回復するには、の試みるべきです。時には、それは適切であるが、RuntimeExceptionsをキャッチしないのJavaのアドバイスは、正当な理由のためにそこにあります。ごくまれに、それは彼らが存在する理由である、1をキャッチすることをお勧めします。ほとんど常にそれが、彼らはとにかくプログラムを停止(あるいは少なくともスレッド)に達することを意味し、それらをキャッチすることはお勧めできません。
他のヒント
あなたは、戻り値は例外ではないことを認識することは例外で記事のカップルをお読みください。ないC 'で、バンドの方法または他の方法ででています。
深い議論に行くがなければ、例外はエラー状態が見つかり、エラー状態が有意義に処理することができる場所捕獲された場合にスローされることを意図しています。戻り値は、のみ、または問題を処理することができなかったことができるかという、非常に最初の関数まで階層スタックで処理されます。簡単な例では、文字列として値を取得することができ、設定ファイルである、とも入力されたreturn文に処理をサポートしています。
class config {
// throws key_not_found
string get( string const & key );
template <typename T> T get_as( string const & key ) {
return boost::lexical_cast<T>( get(key) );
}
};
さて、問題は鍵が見つからなかった場合は、取り扱い行う方法です。あなたは(ゴーのように言う)リターンコードを使用している場合は問題がget_as
がget
からのエラーコードを処理し、それに応じて行動しなければならないということです。それは本当に何をすべきかわからないので、唯一の賢明な事は、の手動の上流のエラーを伝播されます:
class config2 {
pair<string,bool> get( string const & key );
template <typename T> pair<T,bool> get_as( string const & key ) {
pair<string,bool> res = get(key);
if ( !res.second ) {
try {
T tmp = boost::lexical_cast<T>(res.first);
} catch ( boost::bad_lexical_cast const & ) {
return make_pair( T(), false ); // not convertible
}
return make_pair( boost::lexical_cast<T>(res.first), true );
} else {
return make_pair( T(), false ); // error condition
}
}
}
クラスの実装は、エラーを転送するために余分なコードを追加する必要があり、そのコードは、問題の実際のロジックと混在します。 C ++では、これはおそらく、複数の割り当て(a,b=4,5
)用に設計された言語よりも負担ですが、ロジックが可能なエラーによって異なります(私たちは実際の文字列を持っている場合は、ここで呼び出すlexical_cast
でのみ実行されなければならない)場合には、まだ、あなたはする必要がありますキャッシュはとにかく変数に値ます。
ではなく、ユーザは、複数の戻りが非常に多くの方に熟取り扱いに例外をスローしました。
まった場合には、
function divide(top,bottom)
if bottom == 0 then
error("cannot divide by zero")
else
return top/bottom
end
end
その時 bottom
したが0のとき、例外が引き上げられるほか、プログラムの実行うのを止めない限りに包まれる機能 divide
a pcall
(または保護されています。.
pcall
常に値を返します:第一に、結果をbooleanいるかどうかの機能が正常に返された、第二の成果は、いずれかの戻り値またはエラーメッセージを表示します。
以下の(逆)Luaスニペットを示してこの利用
local top, bottom = get_numbers_from_user()
local status, retval = pcall(divide, top, bottom)
if not status then
show_message(retval)
else
show_message(top .. " divided by " .. bottom .. " is " .. retval)
end
もちろん継続してご利用いただけ利用 pcall
, 場の機能だけ呼び出しで返しまの形で status, value_or_error
.
複数の戻りしていLua数年間なのでリスペクトしながら、しない の確保 るのでなく、支援のためのアイデアです。
あり、エラー戻り値は、いくつかの素敵な捉えることの本当の意味を例外扱いる---それができる能力や経営の例外的な場合は通常い。
Java(例)設計例外と考えてIMOのを有効なワークフロー シナリオ というポイントについて、複雑なインタフェースと図書館を宣言するとバージョンこれらのスローされた例外が、alasの例外の重要な役割のスタックーンズ。
思いの場合には例外をスローするコードは条件付きで取り扱う数十メソッドの呼び出します。うスタックトレースのように見える条件に違反した行番号。
この質問は客観的に答えるために少しトリッキーで、例外の意見は非常に多く異なることがあります。
私は推測していた場合は、しかし、私はそれがコンパイラを複雑にし、ライブラリを書くときに非自明な意味合いにつながる可能性があるため、例外が行くには含まれていない主な理由があると思います。例外権利を取得するのは難しいです、そして彼らが働いて何かを得て優先順位を付けます。
の戻り値と例外によるエラー処理の主な違いは、例外が異常な状態に対処するためのプログラマを強制ということです。あなたが明示的に例外をキャッチしてcatchブロックで何もしないかぎりは、「サイレントエラー」を持つことはできません。一方、あなたはバグの他のタイプにつながることができます関数内どこでも暗黙のリターンポイントを得ます。これは、あなたがメモリを明示的に管理し、あなたが割り当てられている何かへのポインタを失うことはありませんことを確認する必要があるC ++で特に流行している。
C ++での危険な状況の例:
struct Foo {
// If B's constructor throws, you leak the A object.
Foo() : a(new A()), b(new B()) {}
~Foo() { delete a; delete b; }
A *a;
B *b;
};
複数の戻り値は、それが簡単に機能を実行引数に依存することなく、戻り値に基づくエラー処理を実装することができますが、それは根本的に何も変更しません。
いくつかの言語は、複数の戻り値と例外(または同様の機構)の両方を有します。一つの例は、 Luaはをされます。
ここで複数の戻り値は、C ++で働くかもしれない方法の例です。私はこのコードを自分自身を記述しないだろうが、私はそれがこのようなアプローチを使用するように論外完全ではないと思います。
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
// return value type
template <typename T>
struct RV {
int mStatus;
T mValue;
RV( int status, const T & rv )
: mStatus( status ), mValue( rv ) {}
int Status() const { return mStatus; }
const T & Value() const {return mValue; }
};
// example of possible use
RV <string> ReadFirstLine( const string & fname ) {
ifstream ifs( fname.c_str() );
string line;
if ( ! ifs ) {
return RV <string>( -1, "" );
}
else if ( getline( ifs, line ) ) {
return RV <string>( 0, line );
}
else {
return RV <string>( -2, "" );
}
}
// in use
int main() {
RV <string> r = ReadFirstLine( "stuff.txt" );
if ( r.Status() == 0 ) {
cout << "Read: " << r.Value() << endl;
}
else {
cout << "Error: " << r.Status() << endl;
}
}
あなたが「NULL可能」オブジェクトの使用ブーストを行うためのC ++道::