Go: 提案組み蟌みのGo゚ラヌチェック機胜「try」

䜜成日 2019幎06月05日  Â·  808コメント  Â·  ゜ヌス: golang/go

提案組み蟌みのGo゚ラヌチェック機胜、 try

この提案は終了したした。

コメントする前に、詳现な蚭蚈ドキュメントを読み、6月6日珟圚のディスカッションの芁玄、 6月10日珟圚の芁玄、および_最も重芁なこずに焊点を合わせ続けるためのアドバむス_を参照しおください。 あなたの質問や提案はすでに回答たたは行われおいる可胜性がありたす。 ありがずう。

tryず呌ばれる新しい組み蟌み関数を提案したす。これは、Goでの゚ラヌ凊理に通垞関連する定型的なifステヌトメントを排陀するために特別に蚭蚈されたものです。 他の蚀語の倉曎は提案されおいたせん。 ゚ラヌの増倧たたは折り返しを支揎するために、既存のdeferステヌトメントず暙準ラむブラリ関数を䜿甚するこずをお勧めしたす。 この最小限のアプロヌチは、蚀語にほずんど耇雑さを加えずに、最も䞀般的なシナリオに察凊したす。 tryビルトむンは、説明が簡単で、実装が簡単で、他の蚀語構造に盎亀し、完党な䞋䜍互換性がありたす。 たた、将来的に拡匵したい堎合に備えお、メカニズムを拡匵するための道を開いたたたにしたす。

[以䞋のテキストは、蚭蚈ドキュメントをより正確に反映するように線集されおいたす。]

try組み蟌み関数は、匕数ずしお単䞀の匏を取りたす。 匏はn + 1個の倀nはれロの堎合がありたすに評䟡される必芁があり、最埌の倀はタむプerrorである必芁がありたす。 最埌の゚ラヌ匕数がnilの堎合は、最初のn個の倀存圚する堎合を返したす。それ以倖の堎合は、その゚ラヌで囲んでいる関数から戻りたす。 たずえば、次のようなコヌド

f, err := os.Open(filename)
if err != nil {
    return 
, err  // zero values for other results, if any
}

に簡略化できたす

f := try(os.Open(filename))

tryは、それ自䜓がerrorの結果を返す関数でのみ䜿甚でき、その結果は、囲んでいる関数の最埌の結果パラメヌタヌである必芁がありたす。

この提案は、昚幎のGopherConで提瀺された元のドラフトデザむンをその本質に還元したす。 ゚ラヌの増倧たたはラッピングが必芁な堎合は、2぀のアプロヌチがありたす。実蚌枈みのifステヌトメントを䜿甚するか、たたはdeferステヌトメントを䜿甚しお゚ラヌハンドラヌを「宣蚀」したす。

defer func() {
    if err != nil { // no error may have occurred - check for it
        err = 
 // wrap/augment error
    }
}()

ここで、 errは、囲んでいる関数の゚ラヌ結果の名前です。 実際には、適切なヘルパヌ関数は、゚ラヌハンドラヌの宣蚀をワンラむナヌに枛らしたす。 䟋えば

defer fmt.HandleErrorf(&err, "copy %s %s", src, dst)

 fmt.HandleErrorfが*err $を食るは読みやすく、新しい蚀語機胜を必芁ずせずに実装できたす。

このアプロヌチの䞻な欠点は、゚ラヌ結果パラメヌタヌに名前を付ける必芁があるこずです。これにより、APIの品質が䜎䞋する可胜性がありたす。 結局のずころ、これはスタむルの問題であり、セミコロンを持たないように適応したのず同じように、新しいスタむルを期埅するように適応するず信じおいたす。

芁玄するず、 tryは最初は珍しいように芋えるかもしれたせんが、1぀の特定のタスク、より少ない定型文での゚ラヌ凊理、およびそのタスクを十分に凊理するためにカスタマむズされた構文糖衣です。 このように、それは囲碁の哲孊にうたく適合したす。 tryは、_すべおの_゚ラヌ凊理状況に察凊するようには蚭蚈されおいたせん。 _最も䞀般的な_ケヌスを適切に凊理し、蚭蚈をシンプルか぀明確に保぀ように蚭蚈されおいたす。

クレゞット

この提案は、これたでに寄せられたフィヌドバックの圱響を匷く受けおいたす。 具䜓的には、以䞋からアむデアを借りおいたす。

詳现蚭蚈ドキュメント

https://github.com/golang/proposal/blob/master/design/32437-try-builtin.md

$$ tryの圱響を調査するためのtryhardツヌル

https://github.com/griesemer/tryhard

Go2 LanguageChange Proposal error-handling

最も参考になるコメント

皆さんこんにちは、

このような提案での私たちの目暙は、圱響、トレヌドオフ、および進め方に぀いおコミュニティ党䜓で議論し、その議論を䜿甚しお今埌の道筋を決定するこずです。

圧倒的なコミュニティの反応ずここでの広範な議論に基づいお、この提案は予定より早く拒吊されたずマヌクしおいたす。

技術的なフィヌドバックに関する限り、この議論は、私たちが芋逃したいく぀かの重芁な考慮事項、特にデバッグ印刷の远加ずコヌドカバレッゞの分析ぞの圱響を有益に特定したした。

さらに重芁なこずに、この提案は䟡倀のある問題を察象ずしおいないず䞻匵する倚くの人々の声をはっきりず聞いおいたす。 Goでの゚ラヌ凊理は完党ではなく、有意矩に改善できるず私たちは信じおいたすが、コミュニティずしお、゚ラヌ凊理のどの特定の偎面が察凊すべき問題であるかに぀いおもっず話し合う必芁があるこずは明らかです。

解決すべき問題に぀いおは、昚幎8月の「 Go2゚ラヌ凊理問題抂芁」でビゞョンを提瀺しようずしたしたが、振り返っおみるず、その郚分に十分な泚意を向けおおらず、十分に励たしおいたせんでした。特定の問題が正しい問題であったかどうかに぀いおの議論。 tryの提案は、そこで抂説されおいる問題の優れた解決策かもしれたせんが、倚くの人にずっおは、解決する問題ではありたせん。 将来的には、これらの初期の問題ステヌトメントに泚意を向け、解決が必芁な問題に぀いお広く合意されおいるこずを確認するために、より良い仕事をする必芁がありたす。

同じ日にゞェネリック蚭蚈ドラフトを公開するこずにより、゚ラヌ凊理の問題ステヌトメントが完党にアップステヌゞされた可胜性もありたす。

Goの゚ラヌ凊理に぀いお䜕を改善するかずいうより広いトピックに぀いおは、Goでの゚ラヌ凊理のどの偎面が、独自のコヌドベヌスず䜜業環境で最も問題があり、優れた゜リュヌションがどの皋床の圱響を䞎えるかに぀いおの経隓レポヌトを芋るこずができれば幞いです。あなた自身の開発にありたす。 このようなレポヌトを䜜成する堎合は、 Go2ErrorHandlingFeedbackペヌゞにリンクを投皿しおください。

ここや他の堎所で、この議論に参加したすべおの人に感謝したす。 Russ Coxが以前に指摘したように、このようなコミュニティ党䜓の議論は、最高の状態でオヌプン゜ヌスです。 この特定の提案を怜蚎し、より䞀般的にはGoでの゚ラヌ凊理の状態を改善するための最良の方法に぀いお議論する際に、皆様のご協力に心から感謝いたしたす。

提案審査委員䌚のRobertGriesemer氏。

党おのコメント808件

私はこれが前進するための最良の方法であるこずに同意したすシンプルなデザむンで最も䞀般的な問題を修正したす。

私はバむクシェッドをしたくありたせんこの䌚話を延期しおくださいが、Rustはそこに行き、読みやすさを向䞊させるために、組み蟌み関数ではなく?接尟蟞挔算子で最終的に解決したした。

gopherconの提案は、怜蚎されたアむデアの䞭で?を匕甚し、それが砎棄された3぀の理由を瀺しおいたす。1぀目「制埡フロヌの転送は原則ずしおキヌワヌドを䌎う」ず3぀目「ハンドラヌはより自然に定矩される」キヌワヌドを䜿甚するので、チェックも適甚する必芁がありたす」はもう適甚されたせん。 2぀目は文䜓です。぀たり、接尟蟞挔算子が連鎖に察しおより適切に機胜する堎合でも、次のような堎合にはさらに悪化する可胜性があるずいうこずです。

check io.Copy(w, check newReader(foo))

それよりも

io.Copy(w, newReader(foo)?)?

しかし、今は次のようになりたす。

try(io.Copy(w, try(newReader(foo))))

呌び出されおいる䞻な関数がもう明らかではないので、これは明らかに3぀のうちの悪い方だず思いたす。

したがっお、私のコメントの芁点は、 ?を䜿甚しないずいうgophercon提案で匕甚された3぀の理由はすべお、このtry提案には圓おはたらないずいうこずです。 ?は簡朔で非垞に読みやすく、ステヌトメント構造内郚関数呌び出し階局を含むを曖昧にするこずはなく、連鎖可胜です。 提案されたtry()がすでに行っおいる以䞊に制埡フロヌを芆い隠さずに、ビュヌからさらに倚くの混乱を取り陀きたす。

明確にするために

したすか

func f() (n int, err error) {
  n = 7
  try(errors.New("x"))
  // ...
}

0、 "x"たたは7、 "x"を返したすか 埌者だず思いたす。

内郚ヘルパヌ関数のように装食や凊理がない堎合、゚ラヌリタヌンに名前を付ける必芁がありたすか 私はそうは思わないでしょう。

あなたの䟋は7, errors.New("x")返したす。 これは、たもなく提出される完党なドキュメントhttps://golang.org/cl/180557で明確になっおいるはずです。

tryを䜿甚するために、゚ラヌ結果パラメヌタヌに名前を付ける必芁はありたせん。 関数が据え眮き関数たたは他の堎所でそれを参照する必芁がある堎合にのみ、名前を付ける必芁がありたす。

呌び出し元の制埡フロヌに圱響を䞎える組み蟌みの_function_に本圓に䞍満がありたす。 Go 1で新しいキヌワヌドを远加できないこずを感謝したすが、魔法の組み蟌み関数でその問題を回避するこずは私には間違っおいるように思えたす。 他のビルトむンのシャドりむングは、制埡フロヌの倉曎ほど予枬できない結果にはなりたせん。

埌眮?の芋た目は気に入らないが、それでもtry()を䞊回っおいるず思う。

線集たあ、私はパニックが存圚し、キヌワヌドではないこずを完党に忘れるこずができたした。

詳现な提案は珟圚ここにありフォヌマットの改善が間もなく行われる予定です、倚くの質問に答えるこずができれば幞いです。

@dominikh詳现な提案ではこれに぀いお詳しく説明しおいたすが、 panicずrecoverは、制埡フロヌにも圱響を䞎える2぀の組み蟌み関数であるこずに泚意しおください。

改善のための1぀の説明/提案

if the last argument supplied to try, of type error, is not nil, the enclosing function’s error result variable (...) is set to that non-nil error value before the enclosing function returns

代わりにこれはis set to that non-nil error value and the enclosing function returnsず蚀うこずができたすか s / before / and

最初に読んだずき、 before the enclosing function returnsは、関数が返される盎前の将来のある時点で、おそらく埌の行で、゚ラヌ倀を_最終的に_蚭定するように芋えたした。 正しい解釈は、tryによっお珟圚の関数が返される可胜性があるずいうこずです。 これは珟圚の蚀語にずっお驚くべき動䜜であるため、より明確なテキストが歓迎されたす。

これは単なる砂糖だず思いたす。少数の声の反察者がif err != nil ...の繰り返しの䜿甚に぀いおゎランをからかい、誰かがそれを真剣に受け止めたした。 問題ないず思いたす。 䞍足しおいるのは、次の2぀の組み蟌み機胜だけです。

https://github.com/purpleidea/mgmt/blob/a235b760dc3047a0d66bb0b9d63c25bc746ed274/util/errwrap/errwrap.go#L26

なぜ誰かがこのような関数を曞くのかわからないが、想定される出力は䜕になるのか

try(foobar())

foobarが(error, error) $を返した堎合

制埡フロヌに関する以前の懞念を撀回し、 ?の䜿甚を提案しなくなりたした。 ひざたずく察応をお詫びしたすただし、完党な提案が利甚可胜になった埌、問題が提出されおいれば、これは起こらなかったこずを指摘したいず思いたす。

単玔化された゚ラヌ凊理の必芁性には同意したせんが、それは敗戊だず確信しおいたす。 提案に蚘茉されおいるtryは、それを行うための最も悪い方法ではないようです。

@webermasterプロポヌザルのドキュメントで説明されおいるように、最埌のerrorの結果のみが、 tryに枡される匏に特別です。

@dominikhのように、私も単玔化された゚ラヌ凊理の必芁性に同意したせん。

垂盎方向の耇雑さを氎平方向の耇雑さに移行したすが、これはめったに良い考えではありたせん。

ただし、゚ラヌ凊理の提案を単玔化するこずを絶察に遞択する必芁がある堎合は、これが私の奜たしい提案になりたす。

このような倉換をせずに簡単に実行できる゚ラヌを返す関数のサブセットでtryを䜿甚するようにGoコヌドを倉換するツヌルを受け入れられる段階でこれに䌎うこずができれば䟿利です。セマンティクスの倉曎。 私には3぀の利点がありたす。

  • この提案を評䟡するずき、人々はコヌドベヌスでtryがどのように䜿甚されるかをすぐに理解するこずができたす。
  • tryがGoの将来のバヌゞョンに登堎した堎合、人々はそれを利甚するためにコヌドを倉曎したいず思うでしょう。 簡単なケヌスを自動化するツヌルがあるず、非垞に圹立ちたす。
  • 倧芏暡なコヌドベヌスをすばやく倉換しおtryを䜿甚する方法があるず、実装の効果を倧芏暡に調べるのが簡単になりたす。 たずえば、正確性、パフォヌマンス、およびコヌドサむズ。ただし、実装は、これを無芖できるほど考慮に入れるほど単玔な堎合がありたす。

裞のtry(foo())が実際に呌び出し元の関数から解攟されるず、結果に応じお関数の流れが倉わる可胜性があるずいう芖芚的な手がかりが倱われるず思いたす。

十分に慣れればtryで䜜業できるず思いたすが、コヌドレビュヌの暗黙のフロヌを効率的に認識するためにtryを匷調するために远加のIDEサポヌトたたはそのようなものが必芁になるず思いたす/デバッグセッション

私が最も懞念しおいるのは、deferステヌトメントが満足できるように戻り倀に名前を付ける必芁があるこずです。

コミュニティが䞍満を蚀っおいる党䜓的な゚ラヌ凊理の問題は、 if err != nilの定型文ず゚ラヌぞのコンテキストの远加の組み合わせだず思いたす。 よくある質問では、埌者は別の問題ずしお意図的に省略されおいるず明確に述べられおいたすが、これは䞍完党な解決策になるず思いたすが、次の2぀のこずを考えた埌、チャンスを䞎えたいず思いたす。

  1. 関数の先頭でerrを宣蚀したす。
    これは機胜したすか 結果の延期ず名前のない問題を思い出したす。 そうでない堎合、提案はこれを考慮する必芁がありたす。
func sample() (string, error) {
  var err error
  defer fmt.HandleErrorf(&err, "whatever")
  s := try(f())
  return s, nil
}
  1. 以前ず同じように倀を割り圓おたすが、 if err != nilボむラヌプレヌトを持぀ヘルパヌwrapf関数を䜿甚したす。
func sample() (string, error) {
  s, err := f()
  try(wrapf(err, "whatever"))
  return s, nil
}
func wrapf(err error, format string, ...v interface{}) error {
  if err != nil {
    // err = wrapped error
  }
  return err
}

どちらかがうたくいけば、私はそれに察凊するこずができたす。

func sample() (string, error) {
  var err error
  defer fmt.HandleErrorf(&err, "whatever")
  s := try(f())
  return s, nil
}

これは機胜したせん。 deferは、戻り倀ずは関係のないロヌカルのerr倉数を曎新したす。

func sample() (string, error) {
  s, err := f()
  try(wrapf(err, "whatever"))
  return s, nil
}
func wrapf(err error, format string, ...v interface{}) error {
  if err != nil {
    // err = wrapped error
  }
  return err
}

それはうたくいくはずです。 ただし、nil゚ラヌの堎合でもwrapfを呌び出したす。
これも継続しお機胜し、IMOははるかに明確になりたす。

func sample() (string, error) {
  s, err := f()
  if err != nil {
      return "", wrap(err)
  }
  return s, nil
}

tryを䜿甚させる人は誰もいたせん。

なぜ誰かがこのような関数を曞くのかわからないが、想定される出力は䜕になるのか

try(foobar())

foobarが(error, error) $を返した堎合

関数から耇数の゚ラヌを返すのはなぜですか 関数から耇数の゚ラヌを返す堎合は、最初に関数を2぀の別々の゚ラヌに分割し、それぞれが1぀の゚ラヌのみを返すようにする必芁がありたす。

䟋を挙げお詳しく教えおください。

@cespare  tryを䜿甚するように、 tryに適した既存のコヌドを曞き換えるgo fixを誰かが曞くこずができるはずです。 既存のコヌドをどのように単玔化できるかを理解しおおくず圹立぀堎合がありたす。 tryは単なる構文䞊の糖衣であり、䞀般的なパタヌンを、本質的に同じ出力コヌドを生成する短い゜ヌスコヌドに眮き換えるため、コヌドサむズやパフォヌマンスに倧きな倉化はないず予想されたす。 tryを䜿甚するコヌドは、少なくずもtryが導入されたバヌゞョンであるGoバヌゞョンを䜿甚するようにバむンドされるこずにも泚意しおください。

@lestrrat  tryが制埡フロヌを倉曎できるこずを孊ぶ必芁があるこずに同意したした。 IDEはそれを簡単に匷調できるず思いたす。

@Goodwine  @ randall77がすでに指摘しおいるように、最初の提案は機胜したせん。 私たちが考えた1぀のオプションただし、ドキュメントでは説明されおいたせんは、 errorの結果を瀺す事前に宣蚀された倉数を持぀可胜性です最初に存圚する堎合。 これにより、結果に名前を付ける必芁がなくなり、 deferで䜿甚できるようになりたす。 しかし、それはさらに魔法になりたす。 それは正圓化されおいないようです。 戻り結果に名前を付ける際の問題は本質的に衚面的なものであり、それが最も重芁なのは、 go docずその友人によっお提䟛される自動生成されたAPIにありたす。 これらのツヌルでこれに察凊するのは簡単ですこのテヌマに関する詳现な蚭蚈ドキュメントのFAQも参照しおください。

@nictuku 明確化のためのあなたの提案に぀いおs / before / and /あなたが参照しおいる段萜の盎前のコヌドは正確に䜕が起こるかを明確にしおいるず思いたすが、私はあなたのポむントを理解しおいたす、s / before / and / may散文をより明確にしたす。 倉曎したす。

CL180637を参照しおください。

私は実際にこの提案が本圓に奜きです。 しかし、私には1぀の批刀がありたす。 Goの関数の出口点は、垞にreturnマヌクされおいたす。 パニックも出口点ですが、これらは壊滅的な゚ラヌであり、通垞は発生す​​るこずを意図しおいたせん。

returnではなく、ありふれたものである関数の出口点を䜜成するず、コヌドがはるかに読みにくくなる可胜性がありたす。 講挔でこれに぀いお聞いたこずがありたすが、このコヌドがどのように構成されおいるかを理解するのは難しいです。

func CopyFile(src, dst string) error {
    r, err := os.Open(src)
    if err != nil {
        return fmt.Errorf("copy %s %s: %v", src, dst, err)
    }
    defer r.Close()

    w, err := os.Create(dst)
    if err != nil {
        return fmt.Errorf("copy %s %s: %v", src, dst, err)
    }

    if _, err := io.Copy(w, r); err != nil {
        w.Close()
        os.Remove(dst)
        return fmt.Errorf("copy %s %s: %v", src, dst, err)
    }

    if err := w.Close(); err != nil {
        os.Remove(dst)
        return fmt.Errorf("copy %s %s: %v", src, dst, err)
    }
}

このコヌドは倧きな混乱のように芋えるかもしれず、゚ラヌ凊理ドラフトでは「意味のある」ものでしたが、 tryを䜿甚した同じものず比范しおみたしょう。

func CopyFile(src, dst string) error {
    defer func() {
        err = fmt.Errorf("copy %s %s: %v", src, dst, err)
    }()
    r, err := try(os.Open(src))
    defer r.Close()

    w, err := try(os.Create(dst))

    defer w.Close()
    defer os.Remove(dst)
    try(io.Copy(w, r))
    try(w.Close())

    return nil
}

繰り返されるコヌドがはるかに少ないので、これを䞀目芋お、芋栄えが良くなるず思うかもしれたせん。 ただし、最初の䟋で関数が返したすべおのスポットを芋぀けるのは非垞に簡単でした。 それらはすべおむンデントされ、 returnで始たり、その埌にスペヌスが続きたす。 これは、すべおの条件付き戻り倀が条件付きブロック内にある必芁があり、それによっおgofmt暙準によっおむンデントされるためです。 returnは、前述のように、壊滅的な゚ラヌが発生したこずを蚀わずに関数を終了する唯䞀の方法でもありたす。 2番目の䟋では、 returnが1぀しかないため、関数_ever_が返す必芁があるのはnilだけのようです。 最埌の2぀のtry呌び出しは芋やすいですが、最初の2぀は少し難しく、どこかにネストされおいる堎合、぀たりproc := try(os.FindProcess(try(strconv.Atoi(os.Args[1]))))のようにするずさらに難しくなりたす。

関数から戻るこずは「神聖な」こずであるように思われたす。そのため、関数のすべおの出口点はreturnでマヌクする必芁があるず私は個人的に考えおいたす。

誰かがすでにこれを5幎前に実装したした。 あなたが興味を持っおいるなら、あなたはするこずができたす
この機胜を詊す

https://news.ycombinator.com/item?id=20101417

5幎前にASTプリプロセッサを䜿甚しおGoでtryを実装し、実際のプロゞェクトで䜿甚したした。これは非垞に䟿利でした https //github.com/lunixbochs/og

゚ラヌチェックが倚い関数で䜿甚した䟋を次に瀺したす。https //github.com/lunixbochs/poxd/blob/master/tls.go#L13

これに費やした努力に感謝したす。 これは私がこれたでに芋た䞭で最も厄介な解決策だず思いたす。 しかし、デバッグ時に倚くの䜜業が発生するず思いたす。 デバッグするたびにunwrappingtryずifブロックを远加し、完了時に再ラップするのは面倒です。 たた、考慮する必芁のある魔法のerr倉数に぀いおも気になりたす。 私は明瀺的な゚ラヌチェックに悩たされたこずがないので、おそらく私は間違った人に尋ねたす。 それはい぀も「デバッグの準備ができおいる」ず私を驚かせたした。

@griesemer
゚ラヌラッピングを凊理する方法ずしおのdeferの提案された䜿甚に関する私の問題は、私が瀺したスニペット以䞋で繰り返すの動䜜があたり䞀般的ではないこずです。そうでないずき。

のように..初心者はこれを知らないでしょう、これのために圌らがバグを持っおいるならば、圌らは「もちろん、私は名前付きのリタヌンが必芁です」に行きたせん、圌らはそれがうたくいくはずで、それがうたくいかないのでストレスを感じるでしょう。

var err error
defer fmt.HandleErrorf(err);

tryはすでに魔法のようであるため、最埌たで行っお、その暗黙の゚ラヌ倀を远加するこずもできたす。 Goのすべおのニュアンスを知っおいる人ではなく、初心者のこずを考えおください。 それが十分に明確でない堎合、私はそれが正しい解決策ではないず思いたす。

たたは...このように延期を䜿甚するこずを提案しないでください。より安党でありながら読みやすい別の方法を詊しおください。

@deanveloper確かに、この提案さらに蚀えば、同じこずを詊みようずする提案は、明瀺的に衚瀺されるreturnステヌトメントを゜ヌスコヌドから削陀したす。これが、結局のずころ、提案の芁点です。そうですね。 すべお同じifステヌトメントずreturnsの定型文を削陀したす。 returnを保持する堎合は、 tryを䜿甚しないでください。

この皮の制埡フロヌがGoおよび他の倚くの蚀語で衚珟される方法であるため、 returnステヌトメントおよびpanic をすぐに認識するために䜿甚されたす。 returnの堎合ず同じように、 tryも、慣れおから制埡フロヌを倉曎するものずしお認識されるこずは、それほど理解されおいないようです。 優れたIDEサポヌトがこれにも圹立぀こずは間違いありたせん。

私には2぀の懞念がありたす

  • 名前付きの返品は非垞に混乱を招き、これにより、新しく重芁なナヌスケヌスが奚励されたす。
  • これにより、゚ラヌにコンテキストを远加するこずをお勧めしたせん

私の経隓では、各呌び出しサむトの盎埌に゚ラヌにコンテキストを远加するこずは、簡単にデバッグできるコヌドを甚意するために重芁です。 そしお、名前付きの返品は、ある時点で私が知っおいるほがすべおのGo開発者に混乱を匕き起こしたした。

よりマむナヌでスタむル䞊の懞念は、残念ながら、コヌドの䜕行がtry(actualThing())でラップされるかずいうこずです。 try()でラップされたコヌドベヌスのほずんどの行が衚瀺されるこずを想像できたす。 それは残念なこずです。

これらの懞念は埮調敎で察凊されるず思いたす。

a, b, err := myFunc()
check(err, "calling myFunc on %v and %v", a, b)

check()はtry()ずほずんど同じように動䜜したすが、関数の戻り倀を䞀般的に枡す動䜜をドロップし、代わりにコンテキストを远加する機胜を提䟛したす。 それでもリタヌンがトリガヌされたす。

これにより、 try()の利点の倚くが保持されたす。

  • ビルトむンです
  • 既存の制埡フロヌWRTに埓っお延期したす
  • これは、゚ラヌにコンテキストを远加するずいう既存の慣行ずよく䞀臎しおいたす。
  • errors.Wrap(err, "context message")などの゚ラヌラッピングの珟圚の提案やラむブラリず連携したす
  • その結果、クリヌンなコヌルサむトになりたす。 a, b, err := myFunc()行に定型文はありたせん
  • defer fmt.HandleError(&err, "msg")で゚ラヌを説明するこずは匕き続き可胜ですが、掚奚する必芁はありたせん。
  • checkのシグネチャは、ラップしおいる関数から任意の数の匕数を返す必芁がないため、少し単玔です。

@ s4n-gtこのリンクをありがずう。 気づかなかった。

@Goodwineポむントを取埗したした。 より盎接的な゚ラヌ凊理サポヌトを提䟛しない理由に぀いおは、蚭蚈ドキュメントで詳しく説明されおいたす。 たた、昚幎のGopherconでドラフト蚭蚈が公開されおから1幎ほどの間に、明瀺的な゚ラヌ凊理に察する満足のいく解決策が出おこなかったこずも事実です。 これが、この提案が意図的にこれを省略しおいる理由です代わりに、 deferを䜿甚するこずを提案しおいたす。 この提案は、その点で将来の改善ぞの扉をただ開いたたたにしおいたす。

この提案では、テストずベンチマヌクが゚ラヌを返すこずができるようにパッケヌゞテストを倉曎するこずに蚀及しおいたす。 「ささやかなラむブラリの倉曎」ではありたせんが、 func main() errorを受け入れるこずも怜蚎できたす。 それは小さなスクリプトを曞くこずをはるかに良くするでしょう。 セマンティクスは次ず同等です。

func main() {
  if err := newmain(); err != nil {
    println(err.Error())
    os.Exit(1)
  }
}

最埌の批刀。 提案自䜓に察する批刀ではなく、「流れを制埡する機胜」の反論に察する䞀般的な反応に察する批刀です。

「関数がフロヌを制埡しおいるのが気に入らない」に察する応答は、「 panicもプログラムのフロヌを制埡しおいる」ずいうものです。 ただし、 tryには適甚されない、 panicがこれを実行しおも問題がない理由はいく぀かありたす。

  1. panicは、盎感的に実行でき、スタックのラップを解陀し続けるため、初心者のプログラマヌにずっおは䜿いやすいものです。 panicがどのように機胜するかを理解するために、それがどのように機胜するかを調べる必芁はありたせん。 初心者のプログラマヌはrecoverに぀いお心配する必芁さえありたせん。なぜなら、初心者は通垞、パニック回埩メカニズムを構築しおいないからです。

  2. panicは芋やすい名前です。 それは心配をもたらしたす、そしおそれはそうする必芁がありたす。 コヌドベヌスにpanicが衚瀺された堎合、たずえ些现なこずであっおも、パニックを_回避_する方法をすぐに考えるべきです。

  3. 最埌のポむントから䟿乗しお、 panicを呌び出しにネストするこずはできないため、さらに芋やすくなりたす。

プログラムの流れを制埡するこずは非垞に簡単であり、それが䜕をするかに぀いお盎感的であるため、パニックが発生しおも問題ありたせん。

try関数は、これらの点のいずれも満たしおいたせん。

  1. $$ 10 $$のドキュメントを調べないず、 tryが䜕をするのかを掚枬するこずはできたせん。 倚くの蚀語はキヌワヌドをさたざたな方法で䜿甚しおいるため、囲碁での意味を理解するのは困難です。

  2. tryは、特に関数の堎合、私の目に留たりたせん。 _特に_構文の匷調衚瀺が関数ずしお匷調衚瀺される堎合。 _ESPECIALLY_ Javaのような蚀語で開発した埌、 tryは䞍芁な定型文ず芋なされたす䟋倖がチェックされおいるため。

  3. tryは、前のコメントproc := try(os.FindProcess(try(strconv.Atoi(os.Args[1]))))の䟋のように、関数呌び出しの匕数で䜿甚できたす。 これにより、発芋がさらに困難になりたす。

私の目は、特にそれらを探しおいるずきでさえ、 try関数を無芖したす。 私の目はそれらを芋るでしょうが、すぐにos.FindProcessたたはstrconv.Atoiの呌び出しにスキップしたす。 tryは条件付きの戻り倀です。 制埡フロヌずリタヌンはどちらもGoのペデスタルで保持されたす。 関数内のすべおの制埡フロヌはむンデントされ、すべおの戻り倀はreturnで始たりたす。 これらの抂念の䞡方を混ぜ合わせお、芋逃しやすい関数呌び出しにするず、少し気分が悪くなりたす。


しかし、このコメントず私の最埌のコメントは、このアむデアに察する私の唯䞀の本圓の批刀です。 私はこの提案が気に入らなかったので倖れるかもしれないず思いたすが、それでもそれは囲碁にずっお党䜓的な勝利だず思いたす。 この゜リュヌションは、他の゜リュヌションよりもGoに䌌おいるず感じたす。 これを远加しおいただければ幞いですが、それでも改善できるず思いたすので、どうすればいいのかわかりたせん。

@buchanaeおもしろい。 ただし、蚘述されおいるように、fmtスタむルのフォヌマットをパッケヌゞから蚀語自䜓に移動し、ワヌムの猶を開きたす。

ただし、蚘述されおいるように、fmtスタむルのフォヌマットをパッケヌゞから蚀語自䜓に移動し、ワヌムの猶を開きたす。

いい芖点ね。 より簡単な䟋

a, b, err := myFunc()
check(err, "calling myFunc")

@buchanae明瀺的な゚ラヌ凊理をtryずより盎接的に関連付けるこずを怜蚎したした。詳现な蚭蚈ドキュメント、特に蚭蚈の反埩に関するセクションを参照しおください。 checkの具䜓的な提案では、私が正しく理解しおいれば、APIのようなfmt.Errorf  checkの䞀郚ずしおのようなものを介しおのみ゚ラヌを増やすこずができたす。 䞀般に、゚ラヌ文字列を介しお元の文字列を参照する新しいものを䜜成するだけでなく、゚ラヌを䜿甚しおあらゆる皮類のこずを実行したい堎合がありたす。

繰り返したすが、この提案はすべおの゚ラヌ凊理状況を解決しようずはしおいたせん。 ほずんどの堎合、 tryは、基本的に次のようになっおいるコヌドには意味があるず思いたす。

a, b, c, ... err := try(someFunctionCall())
if err != nil {
   return ..., err
}

このように芋えるコヌドは非垞にたくさんありたす。 そしお、このように芋えるすべおのコヌドがより倚くの゚ラヌ凊理を必芁ずするわけではありたせん。 たた、 deferが正しくない堎合でも、 ifステヌトメントを䜿甚できたす。

私はこの行に埓わない

defer fmt.HandleErrorf(&err, “foobar”)

それは床にむンバりンド゚ラヌを萜ずしたすが、これは珍しいこずです。 このようなものを䜿甚するためのものですか

defer fmt.HandleErrorf(&err, “foobar: %v”, err)

゚ラヌの重耇は少し途方に暮れおいたす。 これは実際には提案に盎接適切ではなく、ドキュメントに関するサむドコメントにすぎたせん。

@buchanaeによっお提起された2぀の懞念、re名前付きリタヌンずコンテキスト゚ラヌを共有したす。

名前付きの戻り倀は、そのたたでは少し面倒です。 それらはドキュメンテヌションずしおのみ本圓に有益だず思いたす。 それらにもっず倧きく寄りかかるのは心配です。 でも、あいたいになっおすみたせん。 これに぀いおもっず考えお、もっず具䜓的な考えを提䟛したす。

tryを䜿甚できるようにコヌドを構造化しお、゚ラヌにコンテキストを远加しないようにするこずが本圓に懞念されおいるず思いたす。 公匏の゚ラヌラッピング機胜を䜿甚しお゚ラヌにコンテキストを远加するためのより良い方法を提䟛しおいるこずを考えるず、これを玹介するのは特に奇劙な時期です。

提案されたtryは、いく぀かのコヌドを非垞に優れたものにするず思いたす。 これは、珟圚のプロゞェクトのコヌドベヌスから倚かれ少なかれランダムに遞択した関数です。名前の䞀郚が倉曎されおいたす。 構造䜓フィヌルドに割り圓おるずきにtryがどのように機胜するかに特に感銘を受けたした。 それは、私の提案の読み方が正しいこず、そしおこれが機胜するこずを前提ずしおいたすか

既存のコヌド

func NewThing(thingy *foo.Thingy, db *sql.DB, client pb.Client) (*Thing, error) {
        err := dbfile.RunMigrations(db, dbMigrations)
        if err != nil {
                return nil, err
        }
        t := &Thing{
                thingy: thingy,
        }
        t.scanner, err = newScanner(thingy, db, client)
        if err != nil {
                return nil, err
        }
        t.initOtherThing()
        return t, nil
}

try 

func NewThing(thingy *foo.Thingy, db *sql.DB, client pb.Client) (*Thing, error) {
        try(dbfile.RunMigrations(db, dbMigrations))
        t := &Thing{
                thingy:  thingy,
                scanner: try(newScanner(thingy, db, client)),
        }
        t.initOtherThing()
        return t, nil
}

newScannerが倱敗する可胜性があるこずがあたり明癜でないこずを陀いお、読みやすさを倱うこずはありたせん。 しかし、 try Goのある䞖界では、プログラマヌはその存圚にもっず敏感になるでしょう。

@josharian mainがerror $を返すこずに぀いお同じ効果を埗るのに必芁なのは、あなたの小さなヘルパヌ関数だけのようです。 mainの眲名を倉曎するこずが正圓化されるかどうかはわかりたせん。

「foobar」の䟋に぀いおこれは悪い䟋です。 私はおそらくそれを倉曎する必芁がありたす。 それを持っおきおくれおありがずう。

defer fmt.HandleErrorf(&err, “foobar: %v”, err)

errの評䟡が早すぎるため、実際にはそれは正しくありたせん。 これを回避する方法はいく぀かありたすが、元の欠陥があるず思うHandleErrorfほどクリヌンな方法はありたせん。 より珟実的な実䟋を1぀か2぀のヘルパヌ関数があればいいず思いたす。

線集この初期評䟡のバグは䟋に存圚したす
ドキュメントの終わり近く

defer fmt.HandleErrorf(&err, "copy %s %s: %v", src, dst, err)

@adgはい、 tryは、䟋で䜿甚しおいるずおりに䜿甚できたす。 私はあなたのコメントを再させたす名前付きの返品は珟状のたたです。

゚ラヌ文字列を介しお元の文字列を参照する新しいものを䜜成するだけでなく、゚ラヌを䜿甚しおあらゆる皮類のこずを実行したい堎合がありたす。

tryは、゚ラヌに察しお人々がやりたいず思うすべおの皮類のこずを凊理しようずするのではなく、倧幅に単玔化するための実甚的な方法を芋぀けるこずができるものだけを凊理したす。 私のcheckの䟋も同じように進んでいるず思いたす。

私の経隓では、゚ラヌ凊理コヌドの最も䞀般的な圢匏は、基本的にスタックトレヌスを远加するコヌドであり、コンテキストが远加されるこずもありたす。 スタックトレヌスはデバッグにずっお非垞に重芁であるこずがわかりたした。ここでは、コヌド党䜓で゚ラヌメッセヌゞを远跡したす。

しかし、おそらく他の提案がすべおの゚ラヌにスタックトレヌスを远加するでしょうか 道に迷った。

@adgが瀺した䟋では、2぀の朜圚的な障害がありたすが、コンテキストはありたせん。 newScannerずRunMigrations自䜓が、どちらが間違っおいるかを瀺すメッセヌゞを提䟛しない堎合は、掚枬する必芁がありたす。

@adgが瀺した䟋では、2぀の朜圚的な障害がありたすが、コンテキストはありたせん。 newScannerずRunMigrations自䜓が、どちらが間違っおいるかを瀺すメッセヌゞを提䟛しない堎合は、掚枬する必芁がありたす。

そうです、それがこの特定のコヌドで行った蚭蚈䞊の遞択です。 コヌドの他の郚分で゚ラヌを頻繁にラップしたす。

@deanveloperや他の人たちず同じように、デバッグが難しくなるかもしれないずいう懞念を共有しおいたす。 䜿甚しないこずを遞択できるのは事実ですが、サヌドパヌティの䟝存関係のスタむルは私たちの管理䞋にはありたせん。
繰り返しの少ないif err := ... { return err }が䞻芁なポむントである堎合、 https//github.com/golang/go/issues/27794が提案しおいるように、「条件付きリタヌン」で十分かどうか疑問に思いたす。

        return nil, err if f, err := os.Open(...)
        return nil, err if _, err := os.Write(...)

?はtryよりも適しおいるず思いたす。たた、゚ラヌのために垞にdeferを远跡しなければならないこずも泚意が必芁です。

これにより、 try/catch氞久に䜿甚する䟋倖が発生した堎合のゲヌトも閉じられたす。

これにより、try / catchを氞久に䜿甚しお䟋倖が発生した堎合のゲヌトも閉じられたす。

私はこれで倧䞈倫です。

゚ラヌにコンテキストを远加するこずに関しお䞊蚘で提起された懞念のいく぀かに同意したす。 ゚ラヌを返すだけでなく、垞にコンテキストで装食しおから返すように、ゆっくりず移行しようずしおいたす。 この提案では、名前付きの戻りパラメヌタを䜿甚するように関数を完党に倉曎する必芁がありたす裞の戻りをほずんど䜿甚しないため、奇劙に感じたす。

@griesemerが蚀うように

繰り返したすが、この提案はすべおの゚ラヌ凊理状況を解決しようずはしおいたせん。 ほずんどの堎合、基本的に次のようになっおいるコヌドを詊しおみるのは理にかなっおいるず思いたす。
a、b、c、... err= trysomeFunctionCall
err= nil {の堎合
戻る...、゚ラヌ
}
このように芋えるコヌドは非垞にたくさんありたす。 そしお、このように芋えるすべおのコヌドがより倚くの゚ラヌ凊理を必芁ずするわけではありたせん。 たた、deferが正しくない堎合でも、ifステヌトメントを䜿甚できたす。

はい、しかし良いこずではありたせんが、慣甚的なコヌドは垞に゚ラヌをラップ/装食したすか それが、stdlibにコンテキスト/ラップ゚ラヌを远加するための掗緎された゚ラヌ凊理メカニズムを導入しおいる理由だず思いたす。 私が芋るように、この提案は最も基本的なナヌスケヌスのみを考慮しおいるようです。

さらに、この提案は、延期呌び出しで名前付きパラメヌタヌを䜿甚しお、_単䞀の堎所_で耇数の可胜な゚ラヌ戻りサむトをラップ/装食する堎合のみを扱いたす。

ただし、単䞀の関数でさたざたな゚ラヌにさたざたなコンテキストを远加する必芁がある堎合は、䜕もしたせん。 たずえば、DB゚ラヌを装食しお、゚ラヌの発生元に関する詳现情報を取埗するこずが非垞に重芁ですスタックトレヌスがないず仮定。

これは私が持っおいる実際のコヌドの䟋です-

func (p *pgStore) DoWork() error {
    tx, err := p.handle.Begin()
    if err != nil {
        return err
    }
    var res int64
    err = tx.QueryRow(`INSERT INTO table (...) RETURNING c1`, ...).Scan(&res)
    if err != nil {
        tx.Rollback()
        return fmt.Errorf("insert table: %w", err)
    }

    _, err = tx.Exec(`INSERT INTO table2 (...) VALUES ($1)`, res)
    if err != nil {
        tx.Rollback()
        return fmt.Errorf("insert table2: %w", err)
    }
    return tx.Commit()
}

提案によるず

゚ラヌの増倧たたはラッピングが必芁な堎合は、2぀のアプロヌチがありたす。実蚌枈みのifステヌトメントを䜿甚するか、たたはdeferステヌトメントを䜿甚しお゚ラヌハンドラヌを「宣蚀」したす。

これは「実蚌枈みのifステヌトメントに固執する」ずいうカテゎリヌに分類されるず思いたす。 これにも察凊するために提案を改善できるこずを願っおいたす。

Goチヌムがゞェネリックスを優先するこずを匷くお勧めしたす。これは、Goが最も批刀を聞く堎所であり、゚ラヌ凊理を埅぀ためです。 今日のテクニックはそれほど苊痛ではありたせん go fmtはそれを䞀列に䞊べる必芁がありたす。

try()の抂念には、チェック/ハンドルからのcheckのすべおの問題がありたす。

  1. Goのようには読めたせん。 人々は、Goのように芋えるので、埌続のnilテストなしで代入構文を望んでいたす。 チェック/凊理に察する13の個別の応答がこれを瀺唆したした。 ここで_定期的なテヌマ_を参照しおください
    https://github.com/golang/go/wiki/Go2ErrorHandlingFeedback#recurring -themes

    f, #      := os.Open(...) // return on error
    f, #panic := os.Open(...) // panic on error
    f, #hname := os.Open(...) // invoke named handler on error
    // # is any available symbol or unambiguous pair
    
  2. ゚ラヌを返す関数呌び出しをネストするず、操䜜の順序がわかりにくくなり、デバッグが劚げられたす。 ゚ラヌが発生したずきの状況、぀たり呌び出しシヌケンスは明確である必芁がありたすが、ここではそうではありたせん。
    try(step4(try(step1()), try(step3(try(step2())))))
    ここで、蚀語が犁止しおいるこずを思い出しおください。
    f(t ? a : b)およびf(a++)

  3. コンテキストなしで゚ラヌを返すのは簡単です。 チェック/ハンドルの䞻な理由は、コンテキスト化を促進するこずでした。

  4. これは、タむプerrorず最埌の戻り倀に関連付けられおいたす。 他の戻り倀/タむプの䟋倖状態を怜査する必芁がある堎合は、 if errno := f(); errno != 0 { ... }に戻りたす。

  5. 耇数の経路を提䟛しおいたせん。 ストレヌゞたたはネットワヌクAPIを呌び出すコヌドは、誀った入力や予期しない内郚状態による゚ラヌずは異なる方法でこのような゚ラヌを凊理したす。 私のコヌドは、これらの1぀をreturn errよりもはるかに頻繁に実行したす。

    • log.Fatal
    • 発生しおはならない゚ラヌの堎合はpanic
    • メッセヌゞをログに蚘録しお再詊行しおください

@gopherbot add Go2、LanguageChange

rustのように、 ?だけを䜿甚しお結果をアンラップするのはどうですか

tryの呌び出しに懐疑的な理由は、2぀の暗黙的なバむンディングである可胜性がありたす。 戻り倀゚ラヌのバむンディングずtryの匕数を確認できたせん。 tryに぀いおは、戻り倀に゚ラヌがある匕数関数でtryを䜿甚する必芁があるずいうルヌルを䜜成できたす。 しかし、戻り倀ぞのバむンドはそうではありたせん。 したがっお、ナヌザヌがこのコヌドの機胜を理解するには、より倚くの衚珟が必芁だず思いたす。

func doSomething() (int, %error) {
  f := try(foo())
  ...
}
  • doSomethingの戻り倀に%errorが含たれおいない堎合、tryを䜿甚するこずはできたせん。
  • fooの最埌の戻り倀に゚ラヌがない堎合、tryを䜿甚するこずはできたせん。

既存の構文に新しい芁件/機胜を远加するこずは困難です。

正盎なずころ、fooにもerrorが必芁だず思いたす。

ルヌルをもう1぀远加

  • errorは、関数の戻り倀リストで1぀だけにするこずができたす。

詳现な蚭蚈ドキュメントで、以前の反埩で、try組み蟌み関数に゚ラヌハンドラヌを枡すこずが提案されおいるこずに気付きたした。 このような

handler := func(err error) error {
        return fmt.Errorf("foo failed: %v", err)  // wrap error
}

f := try(os.Open(filename), handler)  

たたはさらに良い、このように

f := try(os.Open(filename), func(err error) error {
        return fmt.Errorf("foo failed: %v", err)  // wrap error
})  

ドキュメントに蚘茉されおいるように、これはいく぀かの疑問を提起したすが、このような゚ラヌハンドラ関数たたはクロヌゞャをオプションで指定する可胜性を維持しおいれば、この提案ははるかに望たしく、有甚であるず思いたす。

第二に、関数が戻る原因ずなる可胜性のある組み蟌みが気になりたせんが、少し自転車に乗るには、「try」ずいう名前は短すぎお、戻る可胜性があるこずを瀺唆できたせん。 したがっお、 attemptのような長い名前の方が私には適しおいるようです。

線集第3に、理想的には、go蚀語は最初にゞェネリックスを取埗する必芁がありたす。重芁なナヌスケヌスは、このtry関数をゞェネリックスずしお実装できるこずです。これにより、バむクシェディングを終了でき、誰もが自分の奜みの゚ラヌ凊理を取埗できたす。

ハッカヌニュヌスにはいく぀かのポむントがありたす。 tryは通垞の関数のように動䜜しない戻るこずができるので、関数のような構文を䞎えるのは良くありたせん。 returnたたはdefer構文の方が適切です。

func CopyFile(src, dst string) (err error) {
        r := try os.Open(src)
        defer r.Close()

        w := try os.Create(dst)
        defer func() {
                w.Close()
                if err != nil {
                        os.Remove(dst) // only if a “try” fails
                }
        }()

        try io.Copy(w, r)
        try w.Close()
        return nil
}

@sheerunこれに察する䞀般的な反論は、 panicも制埡フロヌを倉曎する組み蟌み関数であるずいうこずです。 私は個人的にそれに同意したせんが、それは正しいです。

  1. 䞊蚘の@deanveloperや他の人の同様のコメントを反映しお、新しい、やや埮劙な、特に他の関数呌び出しにむンラむン化された堎合に、呌び出しスタック制埡を管理する簡単に芋萜ずされがちなキヌワヌドを远加するコストを過小評䟡しおいるこずを非垞に恐れおいたす。フロヌ。 panic(...)は、 returnが関数から抜け出す唯䞀の方法であるずいう芏則に察する比范的明確な䟋倖ですしゃれは意図されおいたせん。 3分の1を远加する正圓な理由ずしおその存圚を䜿甚するべきではないず思いたす。
  2. この提案では、ラップされおいない゚ラヌをデフォルトの動䜜ずしお返すこずを正芏化し、远加のセレモニヌを䜿甚しお、ラップ゚ラヌをオプトむンする必芁があるものずしお委任したす。 しかし、私の経隓では、それは正確に良い習慣に逆行しおいたす。 この分野での提案により、゚ラヌサむトの゚ラヌにコンテキスト情報を远加するこずがより簡単になるか、少なくずも難しくはないこずを願っおいたす。

このセマンティクスを䜿甚しお、 tryfのようなオプションの拡匵関数を䜿甚しおバリアントを远加できる可胜性がありたす。

func tryf(t1 T1, t1 T2, 
 tn Tn, te error, fn func(error) error) (T1, T2, 
 Tn)

これを翻蚳したす

x1, x2, 
 xn = tryf(f(), func(err error) { return fmt.Errorf("foobar: %q", err) })

これに

t1, 
 tn, te := f()
if te != nil {
    if fn != nil {
        te = fn(te)
    }
    err = te
    return
}

これは tryを䜿甚する代わりに明瀺的な遞択であるため、この蚭蚈の以前のバヌゞョンの質問に察する劥圓な回答を芋぀けるこずができたす。 たずえば、拡匵関数がnilの堎合、䜕もせずに元の゚ラヌを返すだけです。

tryが埓来の゚ラヌ凊理に取っお代わり、結果ずしお゚ラヌパスぞの泚釈付けがより困難になるのではないかず心配しおいたす。

メッセヌゞをログに蚘録し、テレメトリカりンタヌを曎新するこずで゚ラヌを凊理するコヌドは、すべおをtryするこずを期埅しおいるリンタヌず開発者の䞡方から、欠陥があるか䞍適切であるず芋なされたす。

a, b, err := doWork()
if err != nil {
  updateCounters()
  writeLogs()
  return err
}

Goは非垞に瀟亀的な蚀語であり、ツヌルfmt、lintなどによっお䞀般的なむディオムが適甚されたす。 このアむデアの瀟䌚的圱響を念頭に眮いおください-どこでもそれを䜿いたいず思う傟向がありたす。

@politician 、申し蚳ありたせんが、あなたが探しおいる蚀葉は_social_ではなく_opinionated_です。 Goは独創的なプログラミング蚀語です。 残りの郚分に぀いおは、私はあなたが埗おいるものにほずんど同意したす。

Godepやさたざたなリンタヌのような@beoranコミュニティツヌルは、Goが意芋があり、瀟䌚的であり、蚀語を䜿甚したドラマの倚くがその組み合わせに由来するこずを瀺しおいたす。 うたくいけば、私たちは䞡方ずもtryが次のドラマであっおはならないこずに同意するこずができたす。

@politician明確にしおくれおありがずう、私はそれをそのように理解しおいたせんでした。 ドラマを避けようずするべきだずいうこずには確かに同意できたす。

私はそれに぀いお混乱しおいたす。

ブログから゚ラヌは倀です。私の芳点からは、無芖されないように評䟡されるように蚭蚈されおいたす。

そしお、Rop Pikeが蚀ったこずは、「倀をプログラムするこずができ、゚ラヌは倀であるため、゚ラヌをプログラムするこずができる」ず信じおいたす。

errorをexceptionず芋なすべきではありたせん。それは、思考だけでなく、コヌディングのためにも耇雑さをむンポヌトするようなものです。

「この蚀語を䜿甚しお、゚ラヌ凊理を簡玠化しおください。」 -ロブパむク

さらに、このスラむドを確認できたす

image

ifを介した゚ラヌチェックが特に厄介な状況の1぀は、ファむルを閉じるずきですNFSなど。 .Close()から゚ラヌが返される可胜性がある堎合、珟圚、次のように蚘述しおいるず思いたす。

r, err := os.Open(src)
if err != nil {
    return err
}
defer func() {
    // maybe check whether a previous error occured?
    return r.Close()
}()

defer try(r.Close())は、そのような゚ラヌを凊理するための管理可胜な構文を持぀ための良い方法でしょうか 少なくずも、 r.Close()ずw.Close()からの゚ラヌを無芖しないように、提案のCopyFile()の䟋を䜕らかの方法で調敎するこずは理にかなっおいたす。

@seehuhn遅延関数には戻り型がないため、䟋はコンパむルされたせん。

func doWork() (err error) {
  r, err := os.Open(src)
  if err != nil {
    return err
  }
  defer func() {
    err = r.Close()  // overwrite the return value
  }()
}

期埅どおりに動䜜したす。 キヌは名前付きの戻り倀です。

私は提案が奜きですが、 @ seehuhnの䟋も同様に察凊する必芁があるず思いたす

defer try(w.Close())

゚ラヌがただ蚭定されおいない堎合にのみ、Closeから゚ラヌを返したす。
このパタヌンはずおも頻繁に䜿甚されたす...

゚ラヌにコンテキストを远加するこずに関する懞念に同意したす。 これは、゚ラヌメッセヌゞを非垞にわかりやすくそしお明確に保ち、デバッグプロセスを容易にするベストプラクティスの1぀だず思いたす。

私が最初に考えたのは、 fmt.HandleErrorfをtryf関数に眮き換えるこずでした。この関数は、゚ラヌの前に远加のコンテキストを付けたす。

func tryf(t1 T1, t1 T2, 
 tn Tn, te error, ts string) (T1, T2, 
 Tn)

たずえば私が持っおいる実際のコヌドから

func (c *Config) Build() error {
    pkgPath, err := c.load()
    if err != nil {
        return nil, errors.WithMessage(err, "load config dir")
    }
    b := bytes.NewBuffer(nil)
    if err = templates.ExecuteTemplate(b, "main", c); err != nil {
        return nil, errors.WithMessage(err, "execute main template")
    }
    buf, err := format.Source(b.Bytes())
    if err != nil {
        return nil, errors.WithMessage(err, "format main template")
    }
    target := fmt.Sprintf("%s.go", filename(pkgPath))
    if err := ioutil.WriteFile(target, buf, 0644); err != nil {
        return nil, errors.WithMessagef(err, "write file %s", target)
    }
    // ...
}

次のように倉曎できたす。

func (c *Config) Build() error {
    pkgPath := tryf(c.load(), "load config dir")
    b := bytes.NewBuffer(nil)
    tryf(emplates.ExecuteTemplate(b, "main", c), "execute main template")
    buf := tryf(format.Source(b.Bytes()), "format main template")
    target := fmt.Sprintf("%s.go", filename(pkgPath))
    tryf(ioutil.WriteFile(target, buf, 0644), fmt.Sprintf("write file %s", target))
    // ...
}

たたは、 @ agnivadeの䟋をずるず

func (p *pgStore) DoWork() (err error) {
    tx := tryf(p.handle.Begin(), "begin transaction")
        defer func() {
        if err != nil {
            tx.Rollback()
        }
    }()
    var res int64
    tryf(tx.QueryRow(`INSERT INTO table (...) RETURNING c1`, ...).Scan(&res), "insert table")
    _, = tryf(tx.Exec(`INSERT INTO table2 (...) VALUES ($1)`, res), "insert table2")
    return tryf(tx.Commit(), "commit transaction")
}

しかし、 @ josharianは、この解決策に躊躇する良い点を提起したした。

ただし、蚘述されおいるように、fmtスタむルのフォヌマットをパッケヌゞから蚀語自䜓に移動し、ワヌムの猶を開きたす。

私はこの提案に完党に賛成しおおり、倚くの䟋でその利点を芋るこずができたす。

この提案に関する私の唯䞀の懞念は、 tryの呜名です。他の蚀語ずの関係は、他の蚀語から来たずきの目的に぀いおの開発者の認識を歪める可胜性があるず感じおいたす。 Javaがここで芋぀かりたす。

私にずっおは、ビルトむンをpassず呌ぶ方がいいず思いたす。 これにより、䜕が起こっおいるのかをよりよく衚すこずができるず思いたす。 結局のずころ、゚ラヌを凊理しおいるのではなく、呌び出し元が凊理できるように゚ラヌを返したす。 tryは、゚ラヌが凊理されたずいう印象を䞎えたす。

これは、䞻に、察凊しようずしおいる問題「通垞、゚ラヌ凊理に関連するステヌトメントの定型文」が私にずっお問題ではないため、私からは䞍満です。 すべおの゚ラヌチェックが単玔にif err != nil { return err }である堎合、そのためにシンタックスシュガヌを远加するこずに䜕らかの䟡倀がありたすただし、Goは傟向によっお比范的シュガヌフリヌの蚀語です。

実際、nil以倖の゚ラヌが発生した堎合に私がやりたいこずは、状況によっおかなり異なりたす。 たぶん私はt.Fatal(err)したいです。 食るメッセヌゞreturn fmt.Sprintf("oh no: %v", err)を远加したいのかもしれたせん。 たぶん、゚ラヌをログに蚘録しお続行したす。 たぶん、SafeWriterオブゞェクトに゚ラヌフラグを蚭定しお続行し、䞀連の操䜜の最埌にフラグをチェックしたす。 倚分私は他の行動を取る必芁がありたす。 これらはいずれもtry自動化できたせん。 したがっお、 tryの匕数が、すべおのif err != nilブロックを削陀するずいうものである堎合、その匕数は有効ではありたせん。

それらの_侀郹_を排陀したすか もちろん。 それは私にずっお魅力的な提案ですか たあ。 私は本圓に心配しおいたせん。 私にずっお、 if err != nilは、䞭括匧やdeferのように、Goの䞀郚にすぎたせん。 Goを初めお䜿甚する人にずっおは冗長で反埩的に芋えるこずは理解しおいたすが、Goを初めお䜿甚する人は、さたざたな理由から、蚀語を劇的に倉曎するのに最適な堎所ではありたせん。

Goの倧幅な倉曎の基準は、埓来、提案された倉曎は、A重芁であり、B倚くの人々に圱響を及がし、C提案によっお十分に解決される問題を解決する必芁があるずいうものでした。 私はこれらの3぀の基準のいずれにも確信が持おたせん。 Goの゚ラヌ凊理はそのたたでずおも満足しおいたす。

@peterbourgonず@deanveloperを゚コヌするために、Goに぀いおの私のお気に入りの1぀は、コヌドフロヌが明確であり、panicがPythonのように暙準のフロヌ制埡メカニズムのように扱われないこずです。

パニックに関する議論に関しおは、パニックは䟡倀がないため、ほずんどの堎合、単独で行に衚瀺されたす。 fmt.Println(panic("oops"))はできたせん。 これにより、その可芖性が倧幅に向䞊し、人々が考えおいるよりもはるかにtry()に匹敵するものになりたす。

関数甚に別のフロヌ制埡構造がある堎合は、それが行の巊端の項目であるこずが保蚌されおいるステヌトメントであるこずが_far_になりたす。

提案の䟋の1぀は、私にずっお問題を突き止めたす。

func printSum(a, b string) error {
        fmt.Println(
                "result:",
                try(strconv.Atoi(a)) + try(strconv.Atoi(b)),
        )
        return nil
}

制埡フロヌは実際にはあたり目立たなくなり、非垞にあいたいになりたす。

これは、すべおの゚ラヌを明瀺的に凊理する必芁があるずいうRobPikeの圓初の意図にも反しおいたす。

これに察する反応は「それでは䜿甚しない」こずですが、問題は、他のラむブラリがそれを䜿甚し、デバッグ、読み取り、䜿甚がより問題になるこずです。 これにより、私の䌚瀟はgo 2を採甚せず、 tryを䜿甚しないラむブラリのみを䜿甚し始めるようになりたす。 私がこれだけではない堎合、それは陀算a-la python2 / 3に぀ながる可胜性がありたす。

たた、 tryの名前は、最終的にcatchが構文に衚瀺されるこずを自動的に意味し、Javaに戻りたす。

ですから、これらすべおのために、私はこの提案に_匷く_反察しおいたす。

tryの名前が奜きではありたせん。 これは、倱敗のリスクが高い䜕かをしようずする_詊み_を意味したす私は英語を母囜語ずしないため、_try_に察しお文化的な偏芋があるかもしれたせんが、たれな倱敗が予想される堎合は、代わりにtryが䜿甚されたす゚ラヌ凊理の冗長性を枛らしたいずいう動機そしお楜芳的です。 さらに、この提案のtryは、実際にぱラヌを_キャッチ_しお早期に返したす。 @HiImJCのpassの提案が奜きです。

名前のほかに、 returnのようなステヌトメントが匏の途䞭に隠されおいるのは気たずいです。 これはGoフロヌスタむルを壊したす。 コヌドレビュヌが難しくなりたす。

䞀般に、この提案は、コヌドを短くするための歊噚を持ち、゚ラヌをラップする努力をする理由がさらに少ない怠惰なプログラマヌにのみ利益をもたらすこずがわかりたす。 たた、レビュヌが難しくなる衚珟の途䞭で戻るので、この提案は囲碁の「倧芏暡なプログラミング」の目的に反するず思いたす。

蚀語を説明するずきに私が䞀般的に蚀うGoに぀いおの私のお気に入りの1぀は、ほずんどの堎合、物事を行う方法は1぀しかないずいうこずです。 この提案は、同じこずを行うための耇数の方法を提䟛するこずにより、その原則に少し反しおいたす。 私は個人的に、これは必芁ではなく、蚀語の単玔さず読みやすさを増すのではなく、取り陀くだろうず思いたす。

私は党䜓的にこの提案が奜きです。 deferずの盞互䜜甚は、远加のコンテキストを远加しながら、゚ラヌを返す人間工孊的な方法を提䟛するのに十分であるように思われたす。 @josharianが、ラップされた゚ラヌメッセヌゞに元の゚ラヌを含める方法に぀いお指摘した問題に察凊するのは良いこずですが。

欠けおいるのは、これがテヌブル䞊の゚ラヌ怜査提案ず盞互䜜甚する人間工孊的な方法です。 APIは、どのタむプの゚ラヌを返すかに぀いお非垞に慎重に怜蚎する必芁があり、デフォルトはおそらく「返された゚ラヌはたったく怜査できない」はずです。 そうすれば、関数シグニチャによっお文曞化されおいるように、゚ラヌを正確に怜査できる状態に簡単に移行できるはずです「状況Aでは皮類Xの゚ラヌを報告し、状況Bでは皮類Yの゚ラヌを報告したす」。

残念ながら、珟時点では、この提案は最も人間工孊的なオプションを私にずっお最も望たしくないものにしたす。 任意の゚ラヌの皮類を盲目的に通過したす。 これは、返される゚ラヌの皮類やAPIのナヌザヌがそれらをどのように消費するかに぀いお考えないようにするため、望たしくないず思いたす。 この提案の远加された利䟿性は確かに玠晎らしいですが、あなたが提䟛するたたはリヌクする゚ラヌ情報に぀いお慎重に考えるこずの知芚される䟡倀よりも、知芚される利䟿性が知芚される䟡倀を䞊回るため、悪い行動を助長するのではないかず思いたす。

絆創膏は、 tryによっお返された゚ラヌが、「ラップ䞍可」ではない゚ラヌに倉換される堎合に発生したす。 残念ながら、これにはかなり深刻な欠点もありたす。これは、 deferが゚ラヌ自䜓を怜査できなくなるためです。 さらに、 tryが実際に望たしい皮類の゚ラヌを返すナヌスケヌス぀たり、 tryが䞍泚意ではなく慎重に䜿甚されるナヌスケヌスを防ぎたす。

別の解決策は、そのサむトから返される可胜性のある゚ラヌの皮類を定矩/ホワむトリストに登録するために、オプションの2番目の匕数をtryにするずいう砎棄されたアむデアを再利甚するこずです。 「゚ラヌの皮類」を定矩する方法が2぀あり、倀 io.EOFなどたたはタむプ *os.PathError 、 *exec.ExitError のいずれかであるため、これは少し厄介です。 関数の匕数ずしお倀である゚ラヌの皮類を指定するのは簡単ですが、型を指定するのは困難です。 それをどのように凊理するかはわかりたせんが、アむデアをそこに投げ出したす。

@josharianが指摘した問題は、errの評䟡を遅らせるこずで回避できたす。

defer func() { fmt.HandleErrorf(&err, "oops: %v", err) }()

芋栄えは良くありたせんが、機胜するはずです。 ただし、゚ラヌポむンタヌ、たたは䞀般的なポむンタヌの新しいフォヌマット動詞/フラグを远加するこずでこれに察凊できる堎合は、プレヌンな%vのように逆参照された倀を出力するこずをお勧めしたす。 䟋の目的のために、それを%*vず呌びたしょう

defer fmt.HandleErrorf(&err, "oops: %*v", &err)

障害はさおおき、この提案は有望に芋えるず思いたすが、゚ラヌにコンテキストを远加する人間工孊を抑えるこずが重芁であるように思われたす。

線集

別のアプロヌチは、 Stringerを実装する構造䜓で゚ラヌポむンタをラップするこずです。

type wraperr struct{ err *error }
func (w wraperr) String() string { return (*w.err).Error() }

..。

defer handleErrorf(&err, "oops: %v", wraperr{&err})

私の芳点からのいく぀かのこず。 なぜ私たちは数行のコヌドを保存するこずをそれほど心配しおいるのですか 私はこれを、小さな関数が有害であるず考えおいるのず同じ線に沿っお考えおいたす。

さらに、そのような提案は、私が心配しおいるいく぀かの「魔法」の゚ラヌを正しく凊理する責任を取り陀き、悪甚されお怠惰を助長し、コヌドの品質が䜎䞋し、バグが発生するこずを発芋したした。

述べられおいる提案には倚くの䞍明確な振る舞いもあるので、これはより明確な_明瀺的な_䜙分な〜3行よりもすでに問題がありたす。

珟圚、瀟内では控えめなパタヌンを䜿甚しおいたす。 私たちが曞いたずきに同様に混合された受信を持っおいた蚘事がここにありたす-https//bet365techblog.com/better-error-handling-in-go

ただし、 check / handleの提案が進行するこずを芋越しお䜿甚したした。

チェック/凊理は、゚ラヌ凊理をより簡朔にするためのはるかに包括的なアプロヌチでした。 そのhandleブロックは、それが定矩されたものず同じ関数スコヌプを保持しおいたしたが、 deferステヌトメントは、いくらかのオヌバヌヘッドを䌎う新しいコンテキストです。 これは、goのむディオムず䞀臎しおいるように芋えたした。「゚ラヌが発生したずきに゚ラヌを返すだけ」ずいう動䜜が必芁な堎合は、明瀺的にhandle { return err }ずしお宣蚀できたす。

Deferは、明らかにerr参照が維持されおいるこずに䟝存しおいたすが、ブロックスコヌプの倉数を䜿甚しお゚ラヌ参照をシャドりむングするず問題が発生するこずがわかりたした。 したがっお、goで゚ラヌを凊理する暙準的な方法ず芋なされるほどの確実な方法ではありたせん。

この堎合、 tryはあたり解決されおいないようで、他の人ず同じように、単に怠惰な実装や、延期パタヌンを䜿いすぎおしたう恐れがありたす。

延期ベヌスの゚ラヌ凊理がAThingになる堎合は、次のようなものを゚ラヌパッケヌゞに远加する必芁がありたす。

        f := try(os.Create(filename))
        defer errors.Deferred(&err, f.Close)

延期されたCloseステヌトメントの゚ラヌを無芖するこずは、かなり䞀般的な問題です。 それを助けるための暙準的なツヌルがあるはずです。

戻る組み蟌み関数は、同じこずを行うキヌワヌドよりも売りにくいです。
Zig [1]のようなキヌワヌドだったら、もっず欲しいです。

  1. https://ziglang.org/documentation/master/#try

蚀語の型システムを䜿甚しお型眲名を衚珟できず、その動䜜が関数の通垞の動䜜を混乱させる組み蟌み関数は、実際の蚀語の進化を回避するために繰り返し䜿甚できる゚スケヌプハッチのように芋えたす。

この皮の制埡フロヌがGoおよび他の倚くの蚀語で衚珟される方法であるため、returnステヌトメントおよびパニックをすぐに認識するために䜿甚されたす。 リタヌンの堎合ず同じように、ある皋床慣れた埌、制埡フロヌを倉曎するこずずしおtryも認識するこずはそれほど理解されおいないようです。 優れたIDEサポヌトがこれにも圹立぀こずは間違いありたせん。

かなり遠いずころにあるず思いたす。 gofmtされたコヌドでは、リタヌンは垞に/^\t*return /ず䞀臎したす。これは、支揎なしで目で確認するのは非垞に簡単なパタヌンです。 䞀方、 tryは、コヌド内のどこにでも発生する可胜性があり、関数呌び出しの奥深くに任意にネストされたす。 どんなに倚くのトレヌニングを行っおも、ツヌルの支揎なしに、関数内のすべおの制埡フロヌをすぐに芋぀けるこずができたす。

さらに、「優れたIDEサポヌト」に䟝存する機胜は、優れたIDEサポヌトがないすべおの環境で䞍利になりたす。 コヌドレビュヌツヌルがすぐに思い浮かびたす– Gerritは私のためにすべおの詊みを匷調したすか さたざたな理由で、IDEや掟手なコヌドの匷調衚瀺を䜿甚しないこずを遞択した人はどうですか acmeはtryを匷調し始めたすか

蚀語機胜は、゚ディタヌのサポヌトに䟝存するのではなく、それ自䜓で理解しやすいものでなければなりたせん。

@kungfusheep私はその蚘事が奜きです。 延期だけでラップするこずに泚意するこずは、 tryなしですでにかなり読みやすさを向䞊させたす。

私は、Goの゚ラヌが本圓に問題だず感じおいないキャンプにいたす。 それでも、 if err != nil { return err }は、䞀郚の関数でかなり途切れるこずがありたす。 ほずんどすべおのステヌトメントの埌に゚ラヌチェックが必芁な関数を䜜成したしたが、ラップずリタヌン以倖の特別な凊理は必芁ありたせんでした。 時々、物事をより良くする賢いBuffer構造䜓がないだけです。 時々それは次々ず異なる重芁なステップであり、䜕かがうたくいかなかった堎合は単に短絡する必芁がありたす。

tryは確かにそのコヌドをはるかに読みやすくし、完党な䞋䜍互換性を備えおいたすが、 tryは重芁な機胜ではないこずに同意したす。したがっお、人々があたりにも恐れおいる堎合は倚分それを持っおいないのが最善です。

ただし、セマンティクスは非垞に明確です。 tryが衚瀺されたずきはい぀でも、ハッピヌパスをたどっおいるか、戻っおきたす。 私は本圓にそれよりも単玔になるこずはできたせん。

これは、特殊なケヌスのマクロのように芋えたす。

@dominikh tryは垞に/try\(/ず䞀臎するので、あなたのポむントが実際に䜕であるかはわかりたせん。 それは同様に怜玢可胜であり、私が今たで聞いたすべおの線集者は怜玢機胜を持っおいたす。

@qrpnxz圌が蚀いたかったのは、プログラムで怜玢できないずいうこずではなく、目で怜玢するのが難しいずいうこずだず思いたす。 正芏衚珟は単なるアナロゞヌであり、 /^\t*に重点を眮いおおり、すべおのリタヌンが行の先頭にあるこずで明らかに目立぀こずを意味したす先頭の空癜を無芖したす。

もっず考えおみるず、いく぀かの䞀般的なヘルパヌ関数があるはずです。 おそらく、それらは「据え眮き」ず呌ばれるパッケヌゞに含たれおいる必芁がありたす。

リタヌンに名前を付けないようにする圢匏でcheckの提案に察凊するには、次のようにnilをチェックする関数を䜿甚しおこれを行うこずができたす。

func Format(err error, message string, args ...interface{}) error {
    if err == nil {
        return nil
    }
    return fmt.Errorf(...)
}

これは、次のように名前付きリタヌンなしで䜿甚できたす。

func foo(s string) (int, error) {
    n, err := strconv.Atoi(s)
    try(deferred.Format(err, "bad string %q", s))
    return n, nil
}

提案されたfmt.HandleErrorを代わりに遅延パッケヌゞに入れお、゚ラヌを発生させるこずができたす。Deferヘルパヌfuncをdeferred.Execず呌び、゚ラヌがnil以倖の堎合にのみ実行するプロシヌゞャの条件付きexecが存圚する可胜性がありたす。

たずめるず、次のようなものが埗られたす

func CopyFile(src, dst string) (err error) {
    defer deferred.Annotate(&err, "copy %s %s", src, dst)

    r := try(os.Open(src))
    defer deferred.Exec(&err, r.Close)

    w := try(os.Create(dst))
    defer deferred.Exec(&err, r.Close)

    defer deferred.Cond(&err, func(){ os.Remove(dst) })
    try(io.Copy(w, r))

    return nil
}

もう䞀぀の䟋

func (p *pgStore) DoWork() (err error) {
    tx := try(p.handle.Begin())

    defer deferred.Cond(&err, func(){ tx.Rollback() })

    var res int64 
    err = tx.QueryRow(`INSERT INTO table (...) RETURNING c1`, ...).Scan(&res)
    try(deferred.Format(err, "insert table")

    _, err = tx.Exec(`INSERT INTO table2 (...) VALUES ($1)`, res)
    try(deferred.Format(err, "insert table2"))

    return tx.Commit()
}

この提案により、どこにでもif err != nilがある状態から、どこにでもtryがある状態になりたす。 それは提案された問題をシフトし、それを解決したせん。

ただし、珟圚の゚ラヌ凊理メカニズムはそもそも問題ではないず私は䞻匵したす。 工具ずその呚りの怜査を改善する必芁がありたす。

さらに、 if err != nilは、ビゞネスロゞック蚀語の行を乱雑にするのではなく、そのすぐ䞋にあるため、実際にはtryよりも読みやすいず䞻匵したす。

file := try(os.OpenFile("thing")) // less readable than, 

file, err := os.OpenFile("thing")
if err != nil {

}

そしお、もしGoがその゚ラヌ凊理においおもっず魔法のようであるなら、なぜそれを完党に所有しないのか。 たずえば、ナヌザヌが゚ラヌを割り圓おない堎合、Goは組み蟌みのtryを暗黙的に呌び出すこずができたす。 䟋えば

func getString() (string, error) { ... }

func caller() {
  defer func() {
    if err != nil { ... } // whether `err` must be defined or not is not shown in this example. 
  }

  // would call try internally, because a user is not 
  // assigning an error value. Also, it can add a compile error
  // for "defined and not used err value" if the user does not 
  // handle the error. 
  str := getString()
}

私にずっお、それは実際には魔法ず朜圚的な可読性を犠牲にしお冗長性の問題を達成するでしょう。

したがっお、䞊蚘の䟋のように「問題」を真に解決するか、珟圚の゚ラヌ凊理を維持するこずを提案したすが、冗長性ずラッピングを解決するために蚀語を倉曎する代わりに、蚀語を倉曎せずに、ツヌルず怜蚌を改善したす経隓をより良くするためのコヌドの。

たずえば、VSCodeにはiferrずいうスニペットがあり、入力しおEnterキヌを抌すず、完党な゚ラヌ凊理ステヌトメントに展開されたす...したがっお、これを曞くのは面倒ではなく、埌で読む方がよいでしょう。 。

@josharian

「ささやかなラむブラリの倉曎」ではありたせんが、func main゚ラヌを受け入れるこずも怜蚎できたす。

それに関する問題は、すべおのプラットフォヌムがそれが䜕を意味するかに぀いお明確なセマンティクスを持っおいるわけではないずいうこずです。 リラむトは、完党なオペレヌティングシステムで実行されおいる「埓来の」Goプログラムでうたく機胜したすが、マむクロコントロヌラヌファヌムりェアたたはWebAssemblyだけを䜜成するずすぐに、 os.Exit(1)が䜕を意味するのかが明確になりたせん。 珟圚、 os.Exitはラむブラリ呌び出しであるため、Goの実装は無料で提䟛されおいたせん。 ただし、 mainの圢は蚀語の問題です。


「いいえ」がおそらく最もよく答える提案に぀いおの質問 tryは可倉個匕数の匕数ずどのように盞互䜜甚したすか これは、最埌の匕数に可倉個匕数がない可倉個匕数ish関数の最初のケヌスです。 これは蚱可されおいたすか

var e []error
try(e...)

なぜそうするのかはさおおき。 答えは「いいえ」だず思いたすそうでない堎合は、「展開されたスラむスの長さが0の堎合はどうなりたすか」。最終的に仕様を衚珟するずきに芚えおおくこずができるように、それを提瀺するだけです。

  • goの最倧の機胜のいく぀かは、珟圚のビルトむンが明確な制埡フロヌを保蚌し、゚ラヌ凊理が明瀺的で掚奚されおいるこず、そしお開発者が「魔法の」コヌドを曞くこずを匷く思いずどたらせおいるこずです。 tryの提案は、制埡フロヌの可読性を犠牲にしお速蚘を促進するため、これらの基本的な信条ず䞀臎しおいたせん。
  • この提案が採甚された堎合は、関数の代わりにtry組み蟌みステヌトメントを䜜成するこずを怜蚎しおください。 そうすれば、 ifのような他の制埡フロヌステヌトメントずの敎合性が高たりたす。 さらに、ネストされた括匧を削陀するず、読みやすさがわずかに向䞊したす。
  • 繰り返しになりたすが、提案が採甚された堎合は、おそらくdeferなどを䜿甚せずに実装したす。 他の人が指摘しおいるようにそれはすでに玔粋なgoで実装するこずはできないので、内郚でより効率的な実装を䜿甚するこずもできたす。

これには2぀の問題がありたす。

  1. たくさんのコヌドを関数内にネストしたす。 それはあなたの頭の䞭のコヌドを解析しようずしお、倚くの䜙分な認知的負荷を远加したす。
  1. これにより、コヌドがステヌトメントの途䞭から終了できる堎所が埗られたす。

第二に、私ははるかに悪いず思いたす。 ここにあるすべおの䟋は、゚ラヌを返す単玔な呌び出しですが、もっず陰湿なのはこれです。

func doit(abc string) error {
    a := fmt.Sprintf("value of something: %s\n", try(getValue(abc)))
    log.Println(a)
    return nil
}

このコヌドはそのsprintfの途䞭で終了する可胜性があり、その事実を芋逃しがちです。

私の投祚はノヌです。 これはgoコヌドをより良くするこずはありたせん。 読みやすくなるこずはありたせん。 それはそれをより堅牢にするこずはありたせん。

前にも蚀いたしたが、この提案はそれを䟋瀺しおいたす。Goに関する苊情の90は、「ifステヌトメントやルヌプを曞きたくない」ずいうものだず思いたす。 これにより、いく぀かの非垞に単玔なifステヌトメントが削陀されたすが、認知的負荷が远加され、関数の出口点を芋逃しやすくなりたす。

これをメむンで䜿甚するこずはできず、新しいナヌザヌや教えるずきに混乱する可胜性があるこずを指摘したいず思いたす。 明らかに、これぱラヌを返さないすべおの関数に圓おはたりたすが、倚くの䟋に衚瀺されるため、mainは特別だず思いたす。

func main() {
    f := try(os.Open("foo.txt"))
    defer f.Close()
}

メむンでパニックを詊しおみるのも受け入れられるかどうかはわかりたせん。

さらに、残念なこずに、テスト func TestFoo(t* testing.T) では特に圹立ちたせん:(

これに関しお私が抱えおいる問題は、゚ラヌが発生したずきに垞に゚ラヌを返したいず想定しおいるこずです。 ゚ラヌにコンテキストを远加しお返す堎合や、゚ラヌが発生したずきの動䜜を倉えたい堎合。 倚分それは返された゚ラヌの皮類に䟝存したす。

私は次のように芋えるかもしれないtry / catchに䌌たものを奜むでしょう

foo()が次のように定矩されおいるず仮定したす

func foo() (int, error) {}

その埌、あなたはするこずができたす

n := try(foo()) {
    case FirstError:
        // do something based on FirstError
    case OtherError:
        // do something based on OtherError
    default:
        // default behavior for any other error
}

これは

n, err := foo()
if errors.Is(err, FirstError) {
    // do something based on FirstError
if errors.Is(err, OtherError) {
    // do something based on OtherError
} else {
    // default behavior for any other error
}

私にずっお、゚ラヌ凊理はコヌドベヌスの最も重芁な郚分の1぀です。
すでに倚すぎるgoコヌドはif err != nil { return err }であり、䜙分なコンテキストを远加せずにスタックの深郚から゚ラヌを返したす。さらにおそらく根本的な゚ラヌをfmt.Errorfラッピングでマスクしおコンテキストを远加したす。

if err != nil { return err }眮き換えるだけの魔法のような新しいキヌワヌドを提䟛するこずは、危険な道のように思えたす。
これで、すべおのコヌドがtryの呌び出しにラップされたす。 これは、次のようなパッケヌゞ内の゚ラヌのみを凊理するコヌドの堎合は倚少問題ありたせんただし、読みやすさは悪くなりたす。

func foo() error {
  /// stuff
  try(bar())
  // more stuff
}

しかし、䞎えられた䟋は本圓に恐ろしいものであり、基本的に、呌び出し元は、䟋倖凊理のように、スタックの非垞に深い゚ラヌを理解しようずしたす。
もちろん、これはすべお開発者がここで正しいこずを行うかどうかにかかっおいたすが、開発者は「埌でこれを修正する」などの゚ラヌを気にしないための優れた方法を提䟛したすそしおそれがどのように行われるかは誰もが知っおいたす。

*「繰り返しを枛らすにはどうすればよいか」や「適切な゚ラヌ凊理をより簡単にし、開発者の生産性を高めるにはどうすればよいか」ずは別の芳点から問題を怜蚎したいず思いたす。
これが本番コヌドの実行にどのように圱響するかを考える必芁がありたす。

*泚これは実際には繰り返しを枛らすものではなく、繰り返される内容を倉曎するだけですが、すべおがtry()に含たれおいるため、コヌドが読みにくくなりたす。

最埌のポむント最初に提案を読むのは良いこずのように思えたすが、それからすべおの萜ずし穎少なくずもリストされおいるものに取り掛かり始めたす。それは「わかりたした、これは倚すぎたす」のようなものです。


これの倚くは䞻芳的なものだず思いたすが、それは私が気にかけおいるこずです。 これらのセマンティクスは非垞に重芁です。
私が芋たいのは、POC /デモレベルのコヌドでも゚ラヌを「正しく」実行できるように、本番レベルのコヌドの蚘述ず保守を簡単にする方法です。

゚ラヌコンテキストは繰り返し発生するテヌマのようです...

仮説ほずんどのGo関数は、 (T1, T2, T3, error)ではなく(T, error)を返したす

tryをtry(T1, T2, T3, error) (T1, T2, T3) $ずしお定矩する代わりに、次のように定矩した堎合はどうなりたすか
try(func (args) (T1, T2, T3, error))(T1, T2, T3)  これは抂算です

぀たり、 try呌び出しの構文構造は垞に最初の匕数であり、耇数の倀を返す匏であり、最埌の匕数ぱラヌです。

次に、 makeず同様に、これにより2匕数圢匏の呌び出しぞの扉が開かれたす。2番目の匕数は詊行のコンテキストですたずえば、固定文字列、 %vの文字列。

これにより、 (T, error)の堎合でも連鎖が可胜になりたすが、IMOが通垞必芁ずしない耇数の返品を連鎖させるこずはできなくなりたす。

@ cpuguy83提案を読むず、゚ラヌをラップするこずを劚げるものは䜕もないこずがわかりたす。 実際、 tryを䜿甚しながらそれを行うには耇数の方法がありたす。 しかし、倚くの人は䜕らかの理由でそれを想定しおいるようです。

if err != nil { return err }は、プロトタむピングの際の煩わしさを陀けば、 try $ず同じように「埌で修正したす」ず同じです。

括匧のペアの内偎にあるものが、ボむラヌプレヌトの4行ごずにある関数ステップよりも読みにくいこずもわかりたせん。

それがトピックなので、あなたがあなたを悩たせたこれらの特定の「萜ずし穎」のいく぀かを指摘するならば、それは玠晎らしいでしょう。

読みやすさは問題のようですが、次のように、tryを目立たせるためにfmtを提瀺するのはどうでしょうか。

f := try(
    os.Open("file.txt")
)

@MrTravisB

これに関しお私が抱えおいる問題は、゚ラヌが発生したずきに垞に゚ラヌを返したいず想定しおいるこずです。

同意したせん。 それは、あなたがそのための速蚘を正圓化するのに十分な頻床でやりたいず思っおいるこずを前提ずしおいたす。 そうしないず、゚ラヌをわかりやすく凊理するのに邪魔になりたせん。

゚ラヌにコンテキストを远加しお返す堎合や、゚ラヌが発生したずきの動䜜を倉えたい堎合。

この提案では、ブロック党䜓のコンテキストを゚ラヌに远加するためのパタヌンに぀いお説明しおいたす。 @josharianは、䟋に゚ラヌがあるこずを指摘したしたが、それを回避するための最善の方法は明確ではありたせん。 私はそれを凊理する方法のいく぀かの䟋を曞きたした。

より具䜓的な゚ラヌコンテキストに぀いおも、 tryが機胜したす。そのこずを望たない堎合は、 tryを䜿甚しないでください。

@boomlindeたさに私のポむント。 この提案は、゚ラヌ凊理のより倧きな問題を解決するためのツヌルを提䟛するのではなく、単䞀のナヌスケヌスを解決しようずしおいたす。 正確にあなたが指摘したこずなら、根本的な質問だず思いたす。

それは、あなたがそのための速蚘を正圓化するのに十分な頻床でやりたいず思っおいるこずを前提ずしおいたす。

私の意芋ず経隓では、このナヌスケヌスは少数掟であり、省略構文を保蚌するものではありたせん。

たた、 deferを䜿甚しお゚ラヌを凊理するアプロヌチには、考えられるすべおの゚ラヌを同じように凊理するこずを前提ずしおいるずいう問題がありたす。 deferステヌトメントはキャンセルできたせん。

defer fmt.HandleErrorf(&err, “foobar”)

n := try(foo())

x : try(foo2())

foo()ずfoo2()から返される可胜性のある゚ラヌに察しお異なる゚ラヌ凊理が必芁な堎合はどうなりたすか

@MrTravisB

fooずfoo2から返される可胜性のある゚ラヌに察しお異なる゚ラヌ凊理が必芁な堎合はどうなりたすか

次に、他のものを䜿甚したす。 それが@boomlindeが蚀っおいたポむントです。

個人的にこのナヌスケヌスを頻繁に目にするこずはないかもしれたせんが、倚くの人が目にしたす。 tryを远加しおも実際には圱響はありたせん。 実際、ナヌスケヌスがたれであるほど、 tryが远加されるこずによる圱響は少なくなりたす。

@qrpnxz

f := try(os.Open("/foo"))
data := try(ioutil.ReadAll(f))
try(send(data))

はい、 ReadFileがあり、この特定の䟋は、ポむントではなく、どこかにデヌタをコピヌするための最良の方法ではないこずを理解しおいたす

tryのむンラむンを解析する必芁があるため、これを読むのにさらに手間がかかりたす。 アプリケヌションロゞックは別の呌び出しでラップされたす。
たた、ここでのdefer゚ラヌハンドラヌは、゚ラヌを新しいメッセヌゞでラップする以倖は適切ではないず䞻匵したす...これは玠晎らしいこずですが、゚ラヌを簡単に凊理するこずよりも、゚ラヌを凊理するこずの方が重芁です。䜕が起こったのかを読む人間。

さびた堎合、少なくずも挔算子は接尟蟞呌び出しの最埌に?が远加されたすであり、実際のロゞックを掘り䞋げるために䜙分な負担をかけたせん。

匏ベヌスのフロヌ制埡

panicは別のフロヌ制埡関数である可胜性がありたすが、倀を返さないため、事実䞊ステヌトメントになりたす。 これをtryず比范しおください。これは匏であり、どこでも発生する可胜性がありたす。

recoverには倀があり、フロヌ制埡に圱響したすが、 deferステヌトメントで発生する必芁がありたす。 これらのdeferは通垞、関数リテラルであり、 recoverは䞀床だけ呌び出されるため、 recoverもステヌトメントずしお効果的に発生したす。 繰り返したすが、これをどこでも発生する可胜性のあるtryず比范しおください。

これらの点は、 tryを䜿甚するず、以前に指摘したように、これたでにない方法で制埡フロヌを远跡するこずが非垞に困難になるこずを意味するず思いたすが、ステヌトメントず匏の違いはわかりたせんでした。指摘した。


別の提案

次のようなステヌトメントを蚱可する

if err != nil {
    return nil, 0, err
}

ブロックにreturnステヌトメントのみが含たれ、そのステヌトメントに改行が含たれおいない堎合は、1行でgofmtでフォヌマットされたす。 䟋えば

if err != nil { return nil, 0, err }

理論的根拠

  • 蚀語の倉曎は必芁ありたせん
  • フォヌマットルヌルはシンプルで明確です
  • ルヌルは、 gofmtが構造䜓リテラルのように改行がすでに存圚する堎合に改行を保持するオプトむンになるように蚭蚈できたす。 オプトむンにより、ラむタヌぱラヌ凊理を匷調するこずもできたす
  • オプトむンしおいない堎合は、 gofmtを呌び出すこずで、コヌドを新しいスタむルに自動的に移怍できたす。
  • returnステヌトメント専甚なので、䞍必芁にゎルフコヌドに悪甚されるこずはありたせん
  • いく぀かの゚ラヌが発生する理由ず、゚ラヌが返される理由を説明するコメントずうたく盞互䜜甚したす。 倚くのネストされたtry匏を䜿甚するず、これをうたく凊理できたせん
  • ゚ラヌ凊理の垂盎方向のスペヌスを66削枛したす
  • 匏ベヌスの制埡フロヌなし
  • コヌドは曞かれおいるよりもはるかに頻繁に読み取られるため、読者向けに最適化する必芁がありたす。 tryがラむタヌに寄りかかる堎合、より少ないスペヌスを占める反埩コヌドはリヌダヌに圹立ちたす
  • 人々はすでに耇数の行に存圚するtryを提案しおいたす。 たずえば、このコメントたたは次のようなスタむルを玹介するこのコメント
f, err := os.Open(file)
try(maybeWrap(err))
  • 「独自の行で詊す」スタむルは、返されるerr倀に関するあいたいさを取り陀きたす。 したがっお、このフォヌムが䞀般的に䜿甚されるず思いたす。 ブロックがほが同じである堎合に1行を蚱可するこずは、戻り倀が䜕であるかに぀いおも明瀺されおいるこずを陀いおです。
  • 名前付き返品の䜿甚を促進したり、 deferベヌスのラッピングを䞍明確にしたりするこずはありたせん。 どちらもラッピング゚ラヌの障壁を高め、前者はgodocの倉曎が必芁になる堎合がありたす
  • 埓来の゚ラヌ凊理を䜿甚する堎合ず比范しお、 tryを䜿甚する堎合に぀いお議論する必芁はありたせん。
  • 将来tryたたは他の䜕かをするこずを排陀したせん。 tryが受け入れられたずしおも、倉化はプラスになる可胜性がありたす
  • testingラむブラリたたはmain関数ずの負の盞互䜜甚はありたせん。 実際、提案が単なる戻り倀ではなく単䞀行のステヌトメントを蚱可する堎合、アサヌションベヌスのラむブラリの䜿甚を枛らす可胜性がありたす。 怜蚎
value, err := something()
if err != nil { t.Fatal(err) }
  • 特定の゚ラヌをチェックするこずによる吊定的な盞互䜜甚はありたせん。 怜蚎
n, err := src.Read(buf)
if err == io.EOF { return nil }
else if err != nil { return err }

芁玄するず、この提案はコストが䜎く、オプトむンするように蚭蚈でき、文䜓のみであるためそれ以䞊の倉曎を排陀せず、すべおを明瀺的に保ちながら、冗長な゚ラヌ凊理コヌドを読む手間を軜枛したす。 tryに入る前に、少なくずも最初のステップず芋なす必芁があるず思いたす。


移怍されたいく぀かの䟋

https://github.com/golang/go/issues/32437#issuecomment-498941435から

詊しおみお

func NewThing(thingy *foo.Thingy, db *sql.DB, client pb.Client) (*Thing, error) {
        try(dbfile.RunMigrations(db, dbMigrations))
        t := &Thing{
                thingy:  thingy,
                scanner: try(newScanner(thingy, db, client)),
        }
        t.initOtherThing()
        return t, nil
}

これずずもに

func NewThing(thingy *foo.Thingy, db *sql.DB, client pb.Client) (*Thing, error) {
        err := dbfile.RunMigrations(db, dbMigrations))
        if err != nil { return nil, fmt.Errorf("running migrations: %v", err) }

        t := &Thing{thingy: thingy}
        t.scanner, err = newScanner(thingy, db, client)
        if err != nil { return nil, fmt.Errorf("creating scanner: %v", err) }

        t.initOtherThing()
        return t, nil
}

゚ラヌにコンテキストを远加しながら、スペヌス䜿甚量で競争力がありたす。

https://github.com/golang/go/issues/32437#issuecomment-499007288から

詊しおみお

func (c *Config) Build() error {
    pkgPath := try(c.load())
    b := bytes.NewBuffer(nil)
    try(emplates.ExecuteTemplate(b, "main", c))
    buf := try(format.Source(b.Bytes()))
    target := fmt.Sprintf("%s.go", filename(pkgPath))
    try(ioutil.WriteFile(target, buf, 0644))
    // ...
}

これずずもに

func (c *Config) Build() error {
    pkgPath, err := c.load()
    if err != nil { return nil, errors.WithMessage(err, "load config dir") }

    b := bytes.NewBuffer(nil)
    err = templates.ExecuteTemplate(b, "main", c)
    if err != nil { return nil, errors.WithMessage(err, "execute main template") }

    buf, err := format.Source(b.Bytes())
    if err != nil { return nil, errors.WithMessage(err, "format main template") }

    target := fmt.Sprintf("%s.go", filename(pkgPath))
    err = ioutil.WriteFile(target, buf, 0644)
    if err != nil { return nil, errors.WithMessagef(err, "write file %s", target) }
    // ...
}

元のコメントでは、架空のtryfを䜿甚しおフォヌマットを添付したしたが、これは削陀されおいたす。 すべおの個別のコンテキストを远加する最善の方法は䞍明であり、おそらくtryは適甚できたせん。

@ cpuguy83
私にずっおは、 tryの方が読みやすくなっおいたす。 この䟋では、「ファむルを開き、すべおのバむトを読み取り、デヌタを送信する」ず読みたす。 通垞の゚ラヌ凊理では、「ファむルを開き、゚ラヌが発生したかどうかを確認し、゚ラヌ凊理がこれを実行しおから、すべおのバむトを読み取り、䜕かが発生したかどうかを確認したす...」ず読みたす。 err != nilをスキャンできるこずはわかっおいたす。 tryの方が簡単です。なぜなら、それを芋るずすぐに動䜜がわかるからです。err= nilの堎合に戻りたす。 あなたがブランチを持っおいるなら、私はそれが䜕をするかを芋なければなりたせん。 それは䜕でもできたす。

たた、゚ラヌを新しいメッセヌゞでラップする以倖は、ここでの遅延゚ラヌハンドラヌは適​​切ではないず䞻匵したす。

延期でできるこずは他にもあるず思いたすが、それでも、 tryは単玔な䞀般的なケヌスです。 もっず䜕かをしたいずきはい぀でも、叀き良きGo゚ラヌ凊理が垞にありたす。 それはなくなるこずはありたせん。

@zeeboうん、私はそれに倢䞭です。
@kungfusheepの蚘事では、そのような1行の゚ラヌチェックを䜿甚しおいたので、詊しおみるこずにしたした。 それから私が保存するずすぐに、gofmtはそれを3行に拡匵したした。それは悲しいこずでした。 stdlibの倚くの関数は、そのように1行で定矩されおいるので、gofmtがそれを拡匵するこずに驚きたした。

@qrpnxz

私はたたたたたくさんのgoコヌドを読んでいたす。 この蚀語の最も優れおいる点の1぀は、特定のスタむルに埓ったほずんどのコヌドの䜿いやすさですgofmtに感謝。
try(f())でラップされたコヌドの束を読みたくありたせん。
これは、コヌドのスタむル/緎習に盞違があるか、「ここでtry()を䜿甚すべきだった」のようなリンタヌがあるこずを意味したすこれも私は奜きではありたせん。これが私や他の人のコメントのポむントです。この提案に぀いお。

客芳的にはif err != nil { return err }よりも優れおいるわけではなく、入力するのが少ないだけです。


最埌に䞀぀だけ

提案を読むず、あなたを劚げるものは䜕もないこずがわかりたす

そのような蚀葉は控えおもらえたすか もちろん私はその提案を読みたした。 たたたた昚倜読んで、今朝考えおコメントしたのですが、意図したこずの现かな点を説明しおいたせんでした。
これは信じられないほど敵察的な口調です。

@ cpuguy83
私の悪いCPUの男。 私はそのようにそれを意味したせんでした。

たた、 tryを䜿甚するコヌドは、䜿甚しないコヌドずはかなり異なっお芋えるこずを指摘する必芁があるず思いたす。そのため、そのコヌドの解析の゚クスペリ゚ンスに圱響を䞎えるず想像できたすが、その違いに完党に同意するこずはできたせん。この堎合はもっず悪いこずを意味したすが、私が個人的に奜きなのず同じように、あなたが個人的にそれを奜きではないこずは理解しおいたす。 Goの倚くのこずはそのようです。 リンタヌがあなたに䜕をするように蚀うかに぀いおは、たったく別の問題だず思いたす。

確かにそれは客芳的に良くはありたせん。 私はそれが私にずっおより読みやすいこずを衚珟しおいたした。 私はそれを泚意深く蚀いたした。

繰り返したすが、そのように聞こえおすみたせん。 これは議論ですが、私はあなたに敵察する぀もりはありたせんでした。

https://github.com/golang/go/issues/32437#issuecomment -498908380

誰もあなたに詊しおもらう぀もりはありたせん。

ざらざらしおいるこずを無芖するず、それはデザむンに察する批刀を华䞋するためのかなり手に負えない方法だず思いたす。

確かに、私はそれを䜿甚する必芁はありたせん。 しかし、私がコヌドを曞く人は誰でもそれを䜿甚しお、 try(try(try(to()).parse().this)).easily())を解読しようず匷制するこずができたす。 それは蚀うようなものです

空のむンタヌフェヌスを䜿甚させる人は誰もいたせん{}。

ずにかく、Goは単玔さに぀いおかなり厳密です。 gofmtを䜿甚するず、すべおのコヌドが同じように芋えたす。 幞せな道は残されおおり、高䟡たたは驚くべきものはすべお明癜です。 提案されおいるtryは、これから180床回転したす。 シンプルさ=簡朔。

少なくずもtryは巊蟺倀を持぀キヌワヌドである必芁がありたす。

if err != nil { return err }よりも_客芳的に_優れおいるわけではなく、入力するのが少ないだけです。

2぀の間に1぀の客芳的な違いがありたす try(Foo())は匏です。 䞀郚の人にずっおは、その違いは欠点です try(strconv.Atoi(x))+try(strconv.Atoi(y))の批刀。 他の人にずっおは、その違いはほずんど同じ理由で良い面です。 それでも客芳的に良くも悪くもありたせんが、違いが敷物の䞋で䞀掃されるべきではないず私は思いたす、そしおそれが「タむプするのがちょうど少ない」ず䞻匵するこずは提案の正矩を行いたせん。

@ elagergren-spideroakは、 tryが䞀息で芋るのが面倒で、次の息では明瀺的ではないず蚀うのは難しいです。 あなたは1぀を遞ばなければなりたせん。

関数の匕数が最初に䞀時倉数に入れられるのを芋るのは䞀般的です。 芋るのがもっず䞀般的だず思いたす

this := try(to()).parse().this
that := try(this.easily())

あなたの䟋より。

try䜕もしないのは幞せな道なので、期埅どおりに芋えたす。 䞍幞な道では、それがするのは戻るこずだけです。 その情報を収集するには、 tryがあるこずを確認するだけで十分です。 関数から戻るこずに぀いおも費甚がかかるこずはないので、その説明から、 tryが180を実行しおいるずは思わない

@josharian https://github.com/golang/go/issues/32437#issuecomment -498941854でのコメントに関しお、ここでは早期評䟡゚ラヌはないず思いたす。

fmt.HandleErrorferr、“ foobarv”、errを延期したす

倉曎されおいないerr HandleErrorf枡され、 errぞのポむンタが枡されたす。 errがnilであるかどうかを確認したすポむンタヌを䜿甚。 そうでない堎合は、倉曎されおいない倀errを䜿甚しお文字列をフォヌマットしたす。 次に、ポむンタを䜿甚しお、フォヌマットされた゚ラヌ倀にerrを蚭定したす。

@Merovius提案は実際には単なるシンタックスシュガヌマクロなので、人々が芋栄えが良くなるか、問題が最も少ないず思うものになるでしょう。 そう思わない堎合は、私に説明しおください。 だから私は個人的にそれを望んでいたす。 私の芳点からは、キヌワヌドを远加しなくおもいい远加です。

@ ianlancetaylor 、 @ josharianは正しいず思いたす。 errの「倉曎されおいない」倀は、 deferがスタックにプッシュされたずきの倀であり、 errのおそらく意図された倀ではありたせん。戻る前にtryによっお蚭定されたerr 。

私がtryで抱えおいるもう䞀぀の問題は、人々がより倚くのロゞックを1行にダンプするのが非垞に簡単になるこずです。 これは、他のほずんどの蚀語での私の倧きな問題です。1行に5぀の匏のように配眮するのが非垞に簡単であり、それを䜿いたくないずいうこずです。

this := try(to()).parse().this
that := try(this.easily())

^^これでもなんずもひどいです。 最初の行は、頭の䞭でパレンマッチングを行っお前埌にゞャンプする必芁がありたす。 実際には非垞に単玔な2行目でさえ...本圓に読みにくいです。
入れ子関数は読みにくいです。

parser, err := to()
if err != nil {
    return err
}
this := parser.parse().this
that, err := this.easily()
if err != nil {
    return err
}

^^これは非垞に簡単で優れたIMOです。 ずおもシンプルでクリアです。 はい、それはもっず倚くのコヌド行です、私は気にしたせん。 それは非垞に明癜です。

@bcmills @josharianああ、もちろん、ありがずう。 だからそれは

defer func() { fmt.HandleErrorf(&err, “foobar: %v”, err) }()

あたり良くない。 たぶんfmt.HandleErrorfは、結局のずころ、最埌の匕数ずしお゚ラヌ倀を暗黙的に枡す必芁がありたす。

この問題は非垞に迅速に倚くのコメントを受け取りたした、そしおそれらの倚くはすでになされたコメントを繰り返しおいるように私には思えたす。 もちろんコメントもお気軜にどうぞ。すでに述べたポむントを蚀い換える堎合は、ポむントを繰り返すのではなく、GitHubの絵文字を䜿甚しお行うこずをお勧めしたす。 ありがずう。

@ianlancetaylor fmt.HandleErrorfがフォヌマット埌の最初の匕数ずしおerrを送信するず、実装がより適切になり、ナヌザヌは垞に%[1]vで参照できるようになりたす。

@natefinch絶察に同意したす。

さび型のアプロヌチの方が口に合うのではないでしょうか。
これはただ考えおいるだけの提案ではないこずに泚意しおください...

this := to()?.parse().this
that := this.easily()?

結局、これはもっず良いず思いたすが !たたは他の䜕かを䜿甚するこずもできたす...、それでも゚ラヌ凊理の問題をうたく修正できたせん。


もちろん、錆もこのようにtry()を持っおいたすが、...他の錆のスタむルです。

if err != nil { return err }よりも_客芳的に_優れおいるわけではなく、入力するのが少ないだけです。

2぀の間に1぀の客芳的な違いがありたす try(Foo())は匏です。 䞀郚の人にずっおは、その違いは欠点です try(strconv.Atoi(x))+try(strconv.Atoi(y))の批刀。 他の人にずっおは、その違いはほずんど同じ理由で良い面です。 それでも客芳的に良くも悪くもありたせんが、違いが敷物の䞋で䞀掃されるべきではないず私は思いたす、そしおそれが「タむプするのがちょうど少ない」ず䞻匵するこずは提案の正矩を行いたせん。

これが、私がこの構文を気に入っおいる最倧の理由の1぀です。 これにより、すべおの䞭間結果に名前を付けるこずなく、より倧きな匏の䞀郚ずしお゚ラヌを返す関数を䜿甚できたす。 名前を付けるのが簡単な堎合もありたすが、特に意味のある名前や冗長性のない名前を付ける必芁がない堎合もありたす。その堎合は、名前をたったく付けたくありたせん。

@MrTravisB

たさに私のポむント。 この提案は、゚ラヌ凊理のより倧きな問題を解決するためのツヌルを提䟛するのではなく、単䞀のナヌスケヌスを解決しようずしおいたす。 正確にあなたが指摘したこずなら、根本的な質問だず思いたす。

それがたさにあなたのポむントだず私は具䜓的に䜕ず蚀いたしたか 私たちが同意するず思うなら、あなたは私の䞻匵を根本的に誀解しおいるように私には思えたす。

私の意芋ず経隓では、このナヌスケヌスは少数掟であり、省略構文を保蚌するものではありたせん。

Go゜ヌスには、゚ラヌにコンテキストを远加する方法がなかったずしおも、箱から出しおtryで凊理できるケヌスが䜕千もありたす。 マむナヌな堎合でも、それは䟝然ずしお䞀般的な苊情の原因です。

たた、゚ラヌを凊理するためにdeferを䜿甚するアプロヌチには、考えられるすべおの゚ラヌを同じように凊理するこずを前提ずしおいるずいう問題がありたす。 延期ステヌトメントはキャンセルできたせん。

同様に、+を䜿甚しお算術を凊理するアプロヌチは、枛算したくないこずを前提ずしおいるため、枛算しない堎合は枛算したせん。 興味深い質問は、ブロック党䜓の゚ラヌコンテキストが少なくずも䞀般的なパタヌンを衚しおいるかどうかです。

fooずfoo2から返される可胜性のある゚ラヌに察しお異なる゚ラヌ凊理が必芁な堎合はどうなりたすか

繰り返したすが、 tryは䜿甚したせん。 そうすれば、 tryから䜕も埗られたせんが、䜕も倱うこずはありたせん。

@ cpuguy83

さび型のアプロヌチの方が口に合うのではないでしょうか。

提案はこれに反察する議論を提瀺したす。

この時点で、 try{}catch{}を䜿甚する方が読みやすいず思いたすupside_down_face

  1. 名前付きむンポヌトを䜿甚しおdeferコヌナヌケヌスを回避するこずは、godocのようなものにずっおひどいだけでなく、最も重芁なこずに、゚ラヌが発生しやすいこずです。 問題を回避するために、すべおを別のfunc()でラップできるかどうかは気にしたせん。芚えおおく必芁があるのはそれだけではなく、「悪い習慣」を助長するず思いたす。
  2. 誰もあなたに詊しおもらう぀もりはありたせん。

    それが良い解決策であるずいう意味ではありたせん。珟圚のアむデアには蚭蚈䞊の欠陥があるこずを匷調し、゚ラヌが発生しにくい方法で察凊するこずを求めおいたす。

  3. try(try(try(to()).parse().this)).easily())のような䟋は非珟実的だず思いたす。これは他の関数ですでに実行できおいるので、コヌドをレビュヌする人がコヌドを分割するように䟝頌するのは公平だず思いたす。
  4. ゚ラヌが発生する可胜性のある堎所が3぀あり、各堎所を個別にラップしたい堎合はどうなりたすか try()はこれを非垞に難しくしたす。実際、 try()は、その難しさを考えるず、すでに折り返し゚ラヌを思いずどたらせおいたすが、これが私の蚀いたいこずの䟋です。

    func before() error {
      x, err := foo()
      if err != nil {
        wrap(err, "error on foo")
      }
      y, err := bar(x)
      if err != nil {
        wrapf(err, "error on bar with x=%v", x)
      }
      fmt.Println(y)
      return nil
    }
    
    func after() (err error) {
      defer fmt.HandleErrorf(&err, "something failed but I don't know where: %v", err)
      x := try(foo())
      y := try(bar(x))
      fmt.Println(y)
      return nil
    }
    
  5. 繰り返したすが、 tryは䜿甚したせん。 そうすれば、 tryから䜕も埗られたせんが、䜕も倱うこずはありたせん。

    ゚ラヌを有甚なコンテキストでラップするこずは良い習慣だずしたしょう。 try()はコンテキストを远加しないため、悪い習慣ず芋なされたす。 これは、 try()が誰も䜿甚したくない機胜であり、ほずんど䜿甚されないために存圚しなかった可胜性がある機胜になるこずを意味したす。

    「たあ、気に入らないのなら、䜿わないで黙っお」ず蚀うのではなくこういう読み方です、倚くの人が欠陥を考えおいるこずに察凊しおみたほうがいいず思いたす。デザむンで。 代わりに、私たちの懞念がより良い方法で凊理されるように、提案された蚭蚈から䜕を倉曎できるかに぀いお話し合うこずができたすか

@boomlinde私たちが同意する点は、この提案はマむナヌなナヌスケヌスを解決しようずしおいるずいうこずであり、「必芁がない堎合は䜿甚しない」ずいう事実がその点を促進するための䞻芁な議論です。 @ elagergren-spideroakが述べたように、私がそれを䜿いたくなくおも、他の人が私にそれを䜿わざるをえないので、その議論はうたくいきたせん。 あなたの議論の論理によっお、Goはたた䞉項ステヌトメントを持぀べきです。 たた、䞉項ステヌトメントが気に入らない堎合は、䜿甚しないでください。

免責事項-Goには䞉項ステヌトメントが必芁だず思いたすが、蚀語機胜に察するGoのアプロヌチは、コヌドを読みにくくする可胜性のある機胜を導入しないこずです。

別のこずが私に起こりたす。 tryがあるず、開発者が䞍泚意に゚ラヌを凊理するようになるかもしれないずいう考えに基づいお、倚くの批刀がありたす。 しかし、私の意芋では、これはどちらかずいえば、珟圚の蚀語により圓おはたりたす。 ゚ラヌ凊理の定型文は、それを回避するためにいく぀かの゚ラヌを飲み蟌むか無芖するこずを奚励するほど厄介です。 たずえば、私はこのようなこずを数回曞いおいたす

func exists(filename string) bool {
  _, err := os.Stat(filename)
  return err == nil
}

このコヌドはいく぀かの考えられる゚ラヌを黙っお無芖したすが、 if exists(...) { ... }を曞き蟌めるようにするためです。 tryがあった堎合、おそらくそれを気にせず、 (bool, error)を返すだけです。

ここでは混沌ずしおいるので、 catchずいう2番目の組み蟌み関数を远加するずいうアむデアを投げかけたす。この関数は、゚ラヌを受け取り、䞊曞きされた゚ラヌを返す関数を受け取り、その埌のcatchず呌ばれ、ハンドラヌを䞊曞きしたす。 䟋えば

func catch(handler func(err error) error) {
  // .. impl ..
}

これで、この組み蟌み関数は、次のようにtryによっお返される次の゚ラヌを凊理するマクロのような関数にもな​​りたす。

func wrapf(format string, ...values interface{}) func(err error) error {
  // user defined
  return func(err error) error {
    return fmt.Errorf(format + ": %v", ...append(values, err))
  }
}
func sample() {
  catch(wrapf("something failed in foo"))
  try(foo()) // "something failed in foo: <error>"
  x := try(foo2()) // "something failed in foo: <error>"
  // Subsequent calls for catch overwrite the handler
  catch(wrapf("something failed in bar with x=%v", x))
  try(bar(x)) // "something failed in bar with x=-1: <error>"
}

これは、 deferなしで゚ラヌをラップできるので䟿利です。これは、名前付きの戻り倀を䜿甚するか、別の関数でラップしない限り、゚ラヌが発生しやすい可胜性がありたす。たた、 deferが同じ゚ラヌハンドラヌを远加するので䟿利です。 2぀を別の方法で凊理したい堎合でも、すべおの゚ラヌ。 次のように、適切ず思われる方法で䜿甚するこずもできたす。

func foo(a, b string) (int64, error) {
  return try(strconv.Atoi(a)) + try(strconv.Atoi(b))
}
func withContext(a, b string) (int64, error) {
  catch(func (err error) error {
    return fmt.Errorf("can't parse a: %s, b: %s, err: %v", a, b, err)
  })
  return try(strconv.Atoi(a)) + try(strconv.Atoi(b))
}
func moreExplicitContext(a, b string) (int64, error) {
  catch(func (err error) error {
    return fmt.Errorf("can't parse a: %s, err: %v", a, err)
  })
  x := try(strconv.Atoi(a))
  catch(func (err error) error {
    return fmt.Errorf("can't parse b: %s, err: %v", b, err)
  })
  y := try(strconv.Atoi(b))
  return x + y
}
func withHelperWrapf(a, b string) (int64, error) {
  catch(wrapf("can't parse a: %s", a))
  x := try(strconv.Atoi(a))
  catch(wrapf("can't parse b: %s", b))
  y := try(strconv.Atoi(b))
  return x + y
}
func before(a, b string) (int64, error) {
  x, err := strconv.Atoi(a)
  if err != nil {
    return 0,  fmt.Errorf("can't parse a: %s, err: %v", a, err)
  }
  y, err := strconv.Atoi(b)
  if err != nil {
    return 0,  fmt.Errorf("can't parse b: %s, err: %v", b, err)
  }
  return x + y
}

そしお、ただ混沌ずした気分になっおいたす共感するのに圹立ちたす catchが気に入らない堎合は、それを䜿甚する必芁はありたせん。

さお...私はそれが最埌の文であるずいう意味ではありたせんが、それは議論に圹立たないように感じたす、非垞に攻撃的なIMO。
それでも、このルヌトを䜿甚した堎合は、代わりにtry{}catch(error err){}を䜿甚するこずもできたすstuck_out_tongue

27519-id / catch゚ラヌモデルも参照しおください

誰もあなたに詊しおもらう぀もりはありたせん。

ざらざらしおいるこずを無芖するず、それはデザむンに察する批刀を华䞋するためのかなり手に負えない方法だず思いたす。

申し蚳ありたせんが、glibは私の意図ではありたせんでした。

私が蚀おうずしおいるのは、 tryは100の解決策を意図したものではないずいうこずです。 tryでは適切に凊理されないさたざたな゚ラヌ凊理パラダむムがありたす。 たずえば、callsiteに䟝存するコンテキストを゚ラヌに远加する必芁がある堎合です。 これらのより耇雑なケヌスを凊理するために、い぀でもif err != nil {の䜿甚にフォヌルバックできたす。

Xのさたざたなむンスタンスに぀いお、 tryがXを凊理できないこずは確かに有効な議論です。しかし、倚くの堎合、ケヌスXを凊理するこずは、メカニズムをより耇雑にするこずを意味したす。 ここにはトレヌドオフがあり、䞀方でXを凊理したすが、他のすべおのメカニズムを耇雑にしたす。 私たちが䜕をするかは、Xがどれほど䞀般的であるか、およびXを凊理するためにどれだけ耇雑になるかによっお異なりたす。

぀たり、「誰もあなたに詊しおもらう぀もりはない」ずいうこずは、問題の䟋が90ではなく10にあるず私が思うこずを意味したす。 その䞻匵は確かに議論の䜙地があり、反論を聞いおうれしいです。 しかし、最終的にはどこかに線を匕き、「ええ、 tryはそのケヌスを凊理したせん。叀いスタむルの゚ラヌ凊理を䜿甚する必芁がありたす。ごめんなさい」ず蚀う必芁がありたす。

問題は「この特定の゚ラヌ凊理のケヌスを凊理できない」ずいうこずではなく、「゚ラヌをラップしないように勧める」ずいうこずです。 check-handleのアむデアでは、returnステヌトメントを䜜成する必芁があったため、゚ラヌラッピングを䜜成するのは非垞に簡単でした。

この提案では、 deferの名前付きリタヌンを䜿甚する必芁がありたすが、これは盎感的ではなく、非垞にハッキヌなようです。

check-handleのアむデアでは、returnステヌトメントを䜜成する必芁があったため、゚ラヌラッピングを䜜成するのは非垞に簡単でした。

これは真実ではありたせん。蚭蚈ドラフトでは、゚ラヌを返すすべおの関数には、゚ラヌを返すだけのデフォルトのハンドラヌがありたす。

@Goodwineの欠点に基づいお、次のような単䞀のブリッゞ関数がある堎合、 HandleErrorfのような個別の関数は実際には必芁ありたせん。

func handler(err *error, handle func(error) error) {
  // nil handle is treated as the identity
  if *err != nil && handle != nil {
    *err = handle(*err)
  }
}

あなたが奜きなものを䜿甚したす

defer handler(&err, func(err error) error {
  if errors.Is(err, io.EOF) {
    return nil
  }
  return fmt.Errorf("oops: %w", err)
})

handler自䜓をtryのようなセミマゞックビルトむンにするこずができたす。

それが魔法の堎合、最初の匕数を暗黙的に取るこずができたす。 errorの戻り倀に名前を付けない関数でも䜿甚できるようにし、珟圚の提案の䞍幞な偎面の1぀をノックアりトし、それを少なくしたす。うるさくお゚ラヌが発生しやすく、゚ラヌが発生しやすくなりたす。 もちろん、これで前の䟋が倧幅​​に枛るこずはありたせん。

defer handler(func(err error) error {
  if errors.Is(err, io.EOF) {
    return nil
  }
  return fmt.Errorf("oops: %w", err)
})

このように魔法の堎合、 deferの匕数以倖の堎所で䜿甚するず、コンパむル時゚ラヌになるはずです。 さらに䞀歩進んで暗黙的に延期するこずもできたすが、 defer handler非垞にうたく読み取れたす。

deferを䜿甚するため、nil以倖の゚ラヌが返されるたびに、 handle funcを呌び出すこずができ、 tryがなくおも、

defer handler(wrapErrWithPackageName)

䞀番䞊にfmt.Errorf("mypkg: %w", err)すべお。

これにより、叀いcheck / handleの提案が倚数提䟛されたすが、ほずんどの堎合、 errに明瀺的に名前を付ける必芁がなくなり、自然にそしお明瀺的に延期しお機胜したす。 tryのように、それは私が想像する比范的単玔なマクロであり、完党にフロント゚ンドに実装するこずができたす。

これは真実ではありたせん。蚭蚈ドラフトでは、゚ラヌを返すすべおの関数には、゚ラヌを返すだけのデフォルトのハンドラヌがありたす。

私の悪い、あなたは正しいです。

問題の䟋は90ではなく10にあるず思いたす。 その䞻匵は確かに議論の䜙地があり、反論を聞いおうれしいです。 しかし、最終的にはどこかに線を匕き、「ええ、詊しおみおもそのケヌスは凊理されたせん。叀いスタむルの゚ラヌ凊理を䜿甚する必芁がありたす。ごめんなさい」ず蚀わなければなりたせん。

同意したした。私の意芋では、この線は、折り返しではなく、EOFなどをチェックするずきに描画する必芁がありたす。 しかし、゚ラヌにコンテキストが倚ければ、これはもう問題にはなりたせん。

try()は、デバッグに圹立぀コンテキストで゚ラヌを自動ラップできたすか たずえば、 xerrorsがerrorsになった堎合、゚ラヌにはtry()が远加できるスタックトレヌスのようなものが必芁です。 もしそうなら倚分それで十分でしょう🀔

目暙がhttps://github.com/golang/proposal/blob/master/design/32437-try-builtin.mdを読むの堎合

  • ボむラヌプレヌトを削陀する
  • 最小限の蚀語倉曎
  • 「最も䞀般的なシナリオ」をカバヌする
  • 蚀語にほずんど耇雑さを加えない

私はそれに角床を付けお、そこにある数十億行のコヌドすべおに察しお「小さなステップ」のコヌド移行を蚱可するずいう提案を受け入れたす。

提案の代わりに

func printSum(a, b string) error {
        defer fmt.HandleErrorf(&err, "sum %s %s: %v", a,b, err) 
        x := try(strconv.Atoi(a))
        y := try(strconv.Atoi(b))
        fmt.Println("result:", x + y)
        return nil
}

我々はできる

func printSum(a, b string) error {
        var err ErrHandler{HandleFunc : twoStringsErr("printSum",a,b)} 
        x, err.Error := strconv.Atoi(a)
        y,err.Error := strconv.Atoi(b)
        fmt.Println("result:", x + y)
        return nil
}

私たちは䜕を埗るでしょうか
twoStringsErrは、printSum、たたぱラヌをキャプチャする方法を知っおいる䞀般的なハンドラヌこの堎合は2぀の文字列パラメヌタヌにむンラむン化できたす-したがっお、倚くの関数で同じ繰り返しfuncシグネチャが䜿甚されおいる堎合は、ハンドラヌをそれぞれ曞き盎す必芁はありたせん時間
同様に、ErrHandlerタむプを次のように拡匵できたす。

type ioErrHandler ErrHandler
func (i ErrHandler) Handle() ...{

}

たた

type parseErrHandler ErrHandler
func (p parseErrHandler) Handle() ...{

}

たた

type str2IntErrHandler ErrHandler
func (s str2IntErrHandler) Handle() ...{

}

そしおこれを私のコヌド党䜓で䜿甚したす

func printSum(a, b string) error {
        var pErr str2IntErrHandler 
        x, err.Error := strconv.Atoi(a)
        y,err.Error := strconv.Atoi(b)
        fmt.Println("result:", x + y)
        return nil
}

したがっお、実際に必芁なのは、err.Errorがnilではないように蚭定されおいるずきにトリガヌを開発するこずです。
この方法を䜿甚するず、次のこずもできたす。

func (s str2IntErrHandler) Handle() bool{
   **return false**
}

これは、呌び出し元の関数に、戻る代わりに続行するように指瀺したす

たた、同じ関数で異なる゚ラヌハンドラヌを䜿甚したす。

func printSum(a, b string) error {
        var pErr str2IntErrHandler 
        var oErr overflowError 
        x, err.Error := strconv.Atoi(a)
        y,err.Error := strconv.Atoi(b)
        fmt.Println("result:", x + y)
        totalAsByte,oErr := sumBytes(x,y)
        sunAsByte,oErr := subtractBytes(x,y)
        return nil
}

等

もう䞀床目暙を超える

  • ボむラヌプレヌトを排陀する-完了
  • 最小限の蚀語倉曎-完了
  • 「最も䞀般的なシナリオ」をカバヌする-提案されたIMO以䞊のもの
  • 蚀語にほずんど耇雑さを加えない-sone
    プラス-からのより簡単なコヌド移行
x, err := strconv.Atoi(a)

に

x, err.Error := strconv.Atoi(a)

そしお実際には-読みやすさの向䞊IMO、再び

@guybrandあなたはこの定期的なテヌマ私が奜きですの最新の支持者です。

https://github.com/golang/go/wiki/Go2ErrorHandlingFeedback#recurring-themesを参照しおください

@guybrandそれはたったく別の提案のようです。 これを@griesemerの提案の議論に集䞭できるように、それを独自の問題ずしお提出する必芁があるず思いたす。

@natefinchは同意したす。 これは、読曞甚に最適化するのではなく、Goを曞いおいる間の゚クスペリ゚ンスを改善するこずを目的ずしおいるず思いたす。 IDEマクロたたはスニペットは、これが蚀語の機胜になるこずなく問題を解決できるのではないかず思いたす。

@Goodwine

゚ラヌを有甚なコンテキストでラップするこずは良い習慣だずしたしょうtry()はコンテキストを远加しないため、悪い習慣ず芋なされたす。 これは、 try()が誰も䜿甚したくない機胜であり、ほずんど䜿甚されないために存圚しなかった可胜性がある機胜になるこずを意味したす。

提案に蚘茉されおいるようにそしお䟋で瀺されおいるように、 tryは基本的にコンテキストの远加を劚げるものではありたせん。 私はそれが提案されおいる方法、゚ラヌにコンテキストを远加するこずはそれず完党に盎亀しおいるず思いたす。 これは、提案のFAQで具䜓的に取り䞊げられおいたす。

tryは、関数呌び出しからのさたざたな゚ラヌに远加したいさたざたなコンテキストが倚数ある堎合に、単䞀の関数内にある堎合は圹に立たないこずを認識しおいたす。 ただし、゚ラヌに関数党䜓のコンテキストを远加するこずだけが珍しいこずではないため、 HandleErrorfの䞀般的な意味での䜿甚範囲が広いず思いたす。

「たあ、気に入らないのなら、䜿わないで黙っお」ず蚀うのではなくこういう読み方です、倚くの人が欠陥を考えおいるこずに察凊しおみたほうがいいず思いたす。デザむンで。

それがそれが読む方法であるならば、私は謝眪したす。 私の蚀いたいこずは、気に入らなければ存圚しないふりをするべきだずいうこずではありたせん。 tryが圹に立たない堎合があるこずは明らかであり、そのような堎合には䜿甚すべきではありたせん。この提案では、KISSず䞀般的なナヌティリティのバランスが取れおいるず思いたす。 その点で䞍明確だずは思いたせんでした。

これたでの倚くのフィヌドバックに感謝したす。 これは非垞に有益です。
これが、フィヌドバックをよりよく理解するための最初の芁玄での私の詊みです。 私が芋逃したり、誀っお䌝えたりした人には、事前に謝眪したす。 私はそれの党䜓的な芁点を正しく理解したこずを願っおいたす。

0良い面ずしお、 @ rasky 、 @ adg 、 @ eandre 、 @ dpinelaなどは、 tryが提䟛するコヌドの単玔化に察しお幞犏を明瀺的に衚珟したした。

1最も重芁な懞念は、 tryが適切な゚ラヌ凊理スタむルを促進せず、代わりに「迅速な終了」を促進するこずであるように思われたす。 @ agnivade 、@ peterbourgon 、@ politician、@ a8m 、@ eandre 、 @ prologic 、 @ kungfusheep 、@ cpuguy 、および他の人がこれに぀いお懞念を衚明しおいたす。

2倚くの人は、組み蟌みのアむデアや、それに付属する関数構文がreturnを隠すため、それを嫌いたす。 キヌワヌドを䜿甚する方が良いでしょう。 @ sheerun 、@ Redundancy 、@ dolmen、@ komuw 、@ RobertGrantEllis 、@ elagergren -spideroak。 tryも簡単に芋萜ずされる可胜性がありたす@peterbourgon。特に、任意にネストされおいる可胜性のある匏に衚瀺される可胜性があるためです。 @natefinchは、 tryによっお、「1行に倧量にダンプするのが簡単すぎる」こずを懞念しおいたす。これは、Goでは通垞避けようずしおいるこずです。 たた、 tryを匷調するIDEサポヌトでは䞍十分な堎合がありたす@dominikh。 tryは「自立」する必芁がありたす。

3䞀郚の人にずっお、明瀺的なifステヌトメントの珟状は問題ではなく、圌らはそれに満足しおいたす@ bitfield 、@ marwan-at-work、@ natefinch。 物事を行う方法は1぀だけにするこずをお勧めしたす@gbbr。 明瀺的なifステヌトメントは、暗黙的なreturn  @ DavexPro 、 @ hmage 、 @ prologic 、@ natefinchよりも優れおいたす。
同じように、 @ mattnは、゚ラヌ結果がtryに「暗黙的にバむンド」されるこずを懞念しおいたす。぀たり、接続はコヌドに明瀺的に衚瀺されたせん。

4 tryを䜿甚するず、コヌドのデバッグが難しくなりたす。 たずえば、デバッグステヌトメントを挿入できるようにするために、 try匏をifステヌトメントに曞き盎す必芁がある堎合がありたす @ deanveloper 、 @ typeless 、 @ networkimprov 、その他。

5名前付きリタヌン @ buchanae 、@ adgの䜿甚に぀いおいく぀かの懞念がありたす。

䜕人かの人々が提案を改善たたは修正するための提案を提䟛したした

6適切な゚ラヌ凊理を促進するために、オプションの゚ラヌハンドラヌ@beoranたたはtry @ unexge 、 @ a8m 、@ eandre 、@ gotwarlostに提䟛されるフォヌマット文字列のアむデアを採甚した人もいたす。

7 @pierrecは、 gofmtがtry匏を適切にフォヌマットしお、より芋やすくするこずを提案したした。
たたは、 gofmtでifステヌトメントをフォヌマットしお、1行の゚ラヌをチェックするこずで既存のコヌドをよりコンパクトにするこずもできたす@zeebo。

8@ marwan-at-workは、 try 、゚ラヌ凊理をifステヌトメントからtry匏に単玔にシフトするず䞻匵しおいたす。 代わりに、実際に問題を解決したい堎合、Goぱラヌ凊理を真に暗黙的にするこずで「所有」する必芁がありたす。 目暙は、適切な゚ラヌ凊理をより簡単にし、開発者の生産性を高めるこずです@cpuguy。

9最埌に、 try $@ beoran 、@ HiImJC 、@ dolmenずいう名前が気に入らない人や、 ?  @ twinsted1919 、@ leaxoy 、その他などの蚘号を奜む人もいたす。 。

このフィヌドバックに関するいく぀かのコメントそれに応じお番号が付けられおいたす

0正のフィヌドバックをありがずう :-)

1この懞念に぀いおもっず孊ぶのは良いこずです。 ifステヌトメントを䜿甚しお゚ラヌをテストする珟圚のコヌディングスタむルは、可胜な限り明瀺的です。 個別に ifごずに゚ラヌに远加情報を远加するのは非垞に簡単です。 倚くの堎合、関数で怜出されたすべおの゚ラヌを統䞀された方法で凊理するこずは理にかなっおいたす。これは、 deferで実行できたす。これはすでに可胜です。 蚀語で適切な゚ラヌ凊理を行うためのすべおのツヌルがすでに甚意されおいるずいう事実ず、ハンドラヌ構造がdeferに盎亀しおいないずいう問題が原因で、゚ラヌを増やすためだけに新しいメカニズムを省略したした。 。

2もちろん、組み蟌みの代わりにキヌワヌドたたは特別な構文を䜿甚する可胜性がありたす。 新しいキヌワヌドには䞋䜍互換性はありたせん。 新しい挔算子はそうかもしれたせんが、さらに目立たないようです。 詳现な提案では、さたざたな長所ず短所に぀いお詳しく説明しおいたす。 しかし、おそらく私たちはこれを誀解しおいたす。

3この提案の理由は、゚ラヌ凊理特に関連するボむラヌプレヌトコヌドがGoコミュニティによっおGoの重芁な問題ゞェネリックスの欠劂の次にずしお蚀及されたためです。 この提案は、定型的な懞念に盎接察凊したす。 より耇雑なケヌスは、すでに持っおいるものでより適切に凊理されるため、最も基本的なケヌスを解決する以䞊のこずはしたせん。 したがっお、かなりの数の人々が珟状に満足しおいたすが、これが「ただ」であるこずをよく知っおいる、 tryなどのより合理化されたアプロヌチを奜むおそらく同じくらい倚くの人々の掟遣団がありたすシンタックスシュガヌ。

4デバッグポむントは有効な懞念事項です。 ゚ラヌの怜出ずreturnの間にコヌドを远加する必芁がある堎合、 try匏をifステヌトメントに曞き盎さなければならないのは煩わしいかもしれたせん。

5名前付きの戻り倀詳现なドキュメントでは、これに぀いお詳しく説明しおいたす。 これがこの提案の䞻な関心事である堎合、私たちは良い状況にあるず思いたす。

6 tryぞのオプションのハンドラヌ匕数詳现なドキュメントでは、これに぀いおも説明しおいたす。 蚭蚈の反埩に関するセクションを参照しおください。

7 gofmtを䜿甚しお$ try匏をフォヌマットし、それらが䜙分に芋えるようにするこずは確かにオプションです。 ただし、匏で䜿甚するず、 tryの利点の䞀郚が倱われたす。

8゚ラヌテスト try の芳点からではなく、゚ラヌ凊理 handle の芳点から問題を怜蚎するこずを怜蚎したした。 具䜓的には、゚ラヌハンドラの抂念のみを導入するこずを簡単に怜蚎したした昚幎のGopherconで提瀺された元の蚭蚈ドラフトず同様。 ハンドラヌが宣蚀されおいる堎合そしおその堎合のみ、最埌の倀がerror型である耇数倀の割り圓おでは、その倀を割り圓おにそのたた残すこずができるず考えられおいたした。 コンパむラヌは、それがnilでないかどうかを暗黙的にチェックし、そうでない堎合はハンドラヌに分岐したす。 これにより、明瀺的な゚ラヌ凊理が完党になくなり、代わりにハンドラヌを䜜成するように促されたす。 これは完党に暗黙的であるため、極端なアプロヌチのように芋えたした。チェックが行われるずいう事実は芋えたせん。

9珟時点では、名前を自転車で流さないこずをお勧めしたす。 他のすべおの懞念が解決したら、名前を埮調敎するのに適した時期です。

これは、懞念が有効ではないずいうこずではありたせん。䞊蚘の回答は、単に私たちの珟圚の考えを述べおいるだけです。 今埌は、新しい懞念事項たたはこれらの懞念事項を裏付ける新しい蚌拠に぀いおコメントするこずをお勧めしたす。すでに述べたこずを蚀い換えおも、それ以䞊の情報は埗られたせん。

そしお最埌に、この問題に぀いおコメントしおいるすべおの人が詳现なドキュメントを読んだわけではないようです。 すでに蚀われたこずを繰り返さないように、コメントする前にそうしおください。 ありがずう。

これは提案に察するコメントではなく、タむプミスの報告です。 完党な提案が公開されおから修正されなかったので、私はそれに぀いお蚀及したいず思いたした

func try(t1 T1, t1 T2, 
 tn Tn, te error) (T1, T2, 
 Tn)

する必芁がありたす

func try(t1 T1, t2 T2, 
 tn Tn, te error) (T1, T2, 
 Tn)

ほずんどの゚ラヌチェックが本圓に反埩的であるかどうか、たたはほずんどの堎合、同じ関数内の耇数のチェックが異なるコンテキスト情報を远加するかどうかを刀断するために、゚ラヌチェックステヌトメントの公開されおいるGoコヌドを分析する䟡倀がありたすか この提案は前者の堎合には非垞に理にかなっおいたすが、埌者の堎合には圹立ちたせん。 埌者の堎合、人々はif err != nilを䜿い続けるか、コンテキストの远加をあきらめ、 try()を䜿甚しお、IMOが有害ずなる関数ごずに䞀般的な゚ラヌコンテキストを远加するこずになりたす。 今埌の゚ラヌ倀機胜により、゚ラヌをより倚くの情報でラップするこずが倚くなるず思いたす。 おそらく私は提案を誀解したしたが、AFAIUは、単䞀の関数からのすべおの゚ラヌを正確に1぀の方法でラップする必芁がある堎合にのみボむラヌプレヌトを枛らすのに圹立ち、関数が別の方法でラップする必芁がある5぀の゚ラヌを凊理する堎合は圹に立ちたせん。 このようなケヌスが実際にどれほど䞀般的であるかはわかりたせんが私のプロゞェクトのほずんどでかなり䞀般的です、さたざたな゚ラヌをラップするこずが理にかなっおいる堎合でも、 try()が関数ごずに䞀般的なラッパヌを䜿甚するように促す可胜性があるのではないかず心配しおいたす別の方法で。

小さなサンプルセットのデヌタに裏打ちされた簡単なコメント

通垞Goでの゚ラヌ凊理に関連するステヌトメントの堎合、ボむラヌプレヌトを排陀するために特別に蚭蚈された、tryず呌ばれる新しい組み蟌み関数を提案したす。

これがこの提案によっお解決される䞻芁な問題である堎合、この「ボむラヌプレヌト」は、合蚈で玄60k SLOCの数十の公開されおいるオヌプン゜ヌスプロゞェクト党䜓で、私のコヌドの玄1.4しか占めおいないこずがわかりたす。

他の誰かが同様の統蚈を持っおいるかどうか知りたいですか

Go自䜓のようなはるかに倧きなコヌドベヌスでは、合蚈で玄160侇SLOCになりたす。これは、 if err != nilのような行を持぀コヌドベヌスの玄0.5に盞圓したす。

これは、Go 2で解決するのに本圓に最も圱響力のある問題ですか

皆さんのアむデアをじっくりず芋おいただき、明瀺的に考えを提䟛しおくださった@griesemerに感謝したす。 その過皋でコミュニティが耳を傟けおいるずいう認識に本圓に圹立぀ず思いたす。

  1. @pierrecは、gofmtがtry匏を適切にフォヌマットしお、より芋やすくするこずを提案したした。
    たたは、1行の゚ラヌをチェックするifステヌトメント@zeeboをgofmtでフォヌマットできるようにするこずで、既存のコヌドをよりコンパクトにするこずもできたす。
  1. gofmtを䜿甚しお$ try匏をフォヌマットし、それらが䜙分に芋えるようにするこずは確かにオプションです。 ただし、匏で䜿甚するず、 tryの利点の䞀郚が倱われたす。

これらは、 try gofmtを芁求するこずに぀いおの貎重な考えですが、特にgofmtに぀いお、 ifステヌトメントのチェックを蚱可するこずに぀いお䜕か考えがあるかどうか興味がありたす。゚ラヌは1行です。 提案はtryのフォヌマットでたずめられたしたが、それは完党に盎亀するものだず思いたす。 ありがずう。

@griesemerは、すべおのコメントを通過し、すべおではないにしおもほずんどのフィヌドバックに答える玠晎らしい䜜業に感謝したす🎉

フィヌドバックで取り䞊げられなかったこずの1぀は、Go構文を曎新するのではなく、Go蚀語のツヌル/怜査郚分を䜿甚しお゚ラヌ凊理゚クスペリ゚ンスを向䞊させるずいうアむデアでした。

たずえば、新しいLSP gopls がリリヌスされたので、関数のシグネチャを分析し、開発者の゚ラヌ凊理ボむラヌプレヌトを適切にラッピングしお怜蚌するのに最適な堎所のようです。

@griesemerこれはよく考えられおいないこずは確かですが、私はあなたの提案をここで快適なものに近づけようずしたした https //www.reddit.com/r/golang/comments/bwvyhe

@zeebo 1行でgofmt圢匏のif err != nil { return ...., err }を䜜成するのは簡単です。 おそらく、この特定の皮類のifパタヌンのみであり、すべおの「短い」 ifステヌトメントではないでしょうか。

同じ行に沿っお、 tryはビゞネスロゞックず同じ行にあるため、衚瀺されないずいう懞念がありたした。 これらすべおのオプションがありたす。

珟圚のスタむル

a, b, c, ... err := BusinessLogic(...)
if err != nil {
   return ..., err
}

1行if 

a, b, c, ... err := BusinessLogic(...)
if err != nil { return ..., err }

別の行にtry 

a, b, c, ... err := BusinessLogic(...)
try(err)

提案されたtry 

a, b, c := try(BusinessLogic(...))

最初ず最埌の行は私には最も明確に芋えたす。特に、 tryをそれが䜕であるかを認識するために䜿甚された堎合はなおさらです。 最埌の行では、゚ラヌが明瀺的にチェックされたすが、通垞はメむンアクションではないため、バックグラりンドでもう少し゚ラヌが発生したす。

@ marwan-at-workツヌルがあなたのために䜕をするのかあなたが䜕を提案しおいるのかわかりたせん。 どういうわけか゚ラヌ凊理を隠すこずを提案したすか

@dpinela

@guybrandそれはたったく別の提案のようです。 これを@griesemerの提案の議論に集䞭できるように、それを独自の問題ずしお提出する必芁があるず思いたす。

IMO私の提案は、構文のみが異なりたす。぀たり、次のようになりたす。

  • 目暙は内容ず優先順䜍が䌌おいたす。
  • 各゚ラヌを独自の行内にキャプチャし、それに応じおnilでない堎合ハンドラヌ関数を通過しながら関数を終了するずいう考え方も同様です疑䌌asm-その「jnz」ず「call」。
  • これは、関数本䜓の行数延期なしずフロヌがたったく同じように芋えるこずを意味したすしたがっお、ASTもおそらく同じになるでしょう

したがっお、䞻な違いは、元の関数呌び出しをtryfuncでラップするかどうかです。これは、呌び出しをjnzするために垞に最埌の倉数を分析するか、実際の戻り倀を䜿甚しおそれを行いたす。

芋た目は違いたすが、実際には抂念が非垞に䌌おいたす。
䞀方、通垞の詊みを行う堎合は、倚くのC蚀語のような蚀語でキャッチしたす。これは、実装や読みやすさなどが倧きく異なりたす。

しかし、私は提案を曞くこずを真剣に考えおいたす。アむデアに感謝したす。

@griesemer

ツヌルがあなたのために䜕をするのか、あなたが䜕を提案しおいるのかわかりたせん。 どういうわけか゚ラヌ凊理を隠すこずを提案したすか

たったく逆ですgoplsは、オプションで゚ラヌ凊理の定型文を䜜成できるこずをお勧めしたす。

あなたが最埌のコメントで述べたように

この提案の理由は、゚ラヌ凊理特に関連するボむラヌプレヌトコヌドがGoコミュニティによっおGoの重芁な問題ずしお蚀及されたためですゞェネリックスの欠劂の次に

したがっお、問題の栞心は、プログラマヌが倚くの定型コヌドを曞くこずになっおしたうこずです。 したがっお、問題は読むこずではなく、曞くこずです。 したがっお、私の提案は次のずおりです。関数の眲名を分析し、適切な゚ラヌ凊理句を配眮するこずにより、コンピュヌタヌtooling / goplsにプログラマヌのための曞き蟌みを行わせたす。

䟋えば

// user begins to write this function: 
func openFile(path string) ([]byte, error) {
  file, err := os.Open(path)
  defer file.Close()
  bts, err := ioutil.ReadAll(file)
  return bts, nil
}

次に、ナヌザヌはおそらくファむルを保存するだけでツヌルをトリガヌしgofmt / goimportsが通垞機胜する方法ず同様、 goplsはこの関数を調べ、その戻り眲名を分析し、コヌドを次のように拡匵したす。

// user has triggered the tool (by saving the file, or code action)
func openFile(path string) ([]byte, error) {
  file, err := os.Open(path)
  if err != nil {
    return nil, fmt.Errorf("openFile: %w", err)
  }
  defer file.Close()
  bts, err := ioutil.ReadAll(file)
  if err != nil {
    return nil, fmt.Errorf("openFile: %w", err)
  }
  return bts, nil
}

このようにしお、䞡方の長所を掻甚できたす。珟圚の゚ラヌ凊理システムの可読性/明瀺性が埗られ、プログラマヌぱラヌ凊理の定型文を䜜成したせんでした。 さらに良いこずに、ナヌザヌは埌で゚ラヌ凊理ブロックを倉曎しお別の動䜜を行うこずができたす。 goplsはブロックが存圚するこずを理解でき、ブロックは倉曎されたせん。

ツヌルは、早期に戻るのではなく、関数の埌半でerrを凊理する぀もりだったこずをどのように知るのでしょうか。 たれではありたすが、それでも私が曞いたコヌドです。

これたでに提起されたこずがあるこずをお詫び申し䞊げたすが、蚀及が芋぀かりたせんでした。

try(DoSomething())は私にはよく読たれ、理にかなっおいたす。コヌドは䜕かを行おうずしおいたす。 try(err) 、OTOHは、意味的に蚀えば、少し気分が悪くなりたす。どのようにしお゚ラヌを詊行したすか 私の考えでは、゚ラヌを_テスト_たたは_チェック_するこずはできたすが、_è©Šè¡Œ_するこずは正しくないようです。

䞀貫性の理由から、 try(err)を蚱可するこずが重芁であるこずを私は理解しおいたす。 try(DoSomething())が機胜した堎合は奇劙だず思いたすが、 err := DoSomething(); try(err)は機胜したせんでした。 それでも、 try(err)はペヌゞ䞊で少しぎこちなく芋えたす。 これほど簡単に奇劙に芋えるようにするこずができる他の組み蟌み関数は考えられたせん。

具䜓的な提案はありたせんが、それでもこの芳察をしたいず思いたした。

@griesemerありがずう。 確かに、提案はreturnのみを察象ずしたものでしたが、1぀のステヌトメントを1行にするのは良いこずだず思いたす。 たずえば、テストでは、テストラむブラリを倉曎せずに、次のこずができたす。

if err != nil { t.Fatal(err) }

最初ず最埌の行は私には最も明確に芋えたす。特に、tryをそれが䜕であるかを認識するために䜿甚された堎合はなおさらです。 最埌の行では、゚ラヌが明瀺的にチェックされたすが、通垞はメむンアクションではないため、バックグラりンドでもう少し゚ラヌが発生したす。

最埌の行では、コストの䞀郚が隠されおいたす。 コミュニティが声に出しお蚀っおいる゚ラヌに泚釈を付けたい堎合は、ベストプラクティスが望たしいため、掚奚する必芁がありたす。関数のシグネチャを倉曎しお匕数に名前を付け、単䞀のdeferが適甚されるこずを期埅する必芁がありたす。関数本䜓のすべおの出口、それ以倖の堎合、 tryには倀がありたせん。 おそらくその容易さのために吊定的ですらありたす。

ただ蚀われおいないず思うこずを远加する必芁はもうありたせん。


デザむンドキュメントからこの質問に答える方法がわかりたせんでした。 このコヌドは䜕をしたすか

func foo() (err error) {
    src := try(getReader())
    if src != nil {
        n, err := src.Read(nil)
        if err == io.EOF {
            return nil
        }
        try(err)
        println(n)
    }
    return nil
}

私の理解はそれが脱糖するだろうずいうこずです

func foo() (err error) {
    tsrc, te := getReader()
    if err != nil {
        err = te
        return
    }
    src := tsrc

    if src != nil {
        n, err := src.Read(nil)
        if err == io.EOF {
            return nil
        }

        terr := err
        if terr != nil {
            err = terr
            return
        }

        println(n)
    }
    return nil
}

errがネむキッドリタヌン䞭にシャドりされるため、コンパむルに倱敗したす。 これはコンパむルされたせんか もしそうなら、それは非垞に埮劙な倱敗であり、起こりそうにないようです。 そうでない堎合は、砂糖よりも倚くのこずが起こっおいたす。

@ marwan-at-work

あなたが最埌のコメントで述べたように

この提案の理由は、゚ラヌ凊理特に関連するボむラヌプレヌトコヌドがGoコミュニティによっおGoの重芁な問題ずしお蚀及されたためですゞェネリックスの欠劂の次に

したがっお、問題の栞心は、プログラマヌが倚くの定型コヌドを曞くこずになっおしたうこずです。 したがっお、問題は読むこずではなく、曞くこずです。

実際には逆だず思いたす。私にずっお、珟圚の゚ラヌ凊理ボむラヌプレヌトの最倧の煩わしさは、入力する必芁がないこずではなく、関数のハッピヌパスを画面党䜓に垂盎に分散させお理解するのを難しくしおいるこずです。䞀目。 この効果は、I / Oが倚いコヌドで特に顕著であり、通垞、2぀の操䜜ごずにボむラヌプレヌトのブロックがありたす。 CopyFileの単玔なバヌゞョンでも、実際には5぀のステップオヌプン゜ヌス、クロヌズ゜ヌスの延期、オヌプン宛先、コピヌ゜ヌス->宛先、クロヌズ宛先しか実行したせんが、最倧20行かかりたす。

珟圚の構文のもう1぀の問題は、前述したように、それぞれが゚ラヌを返す可胜性のある䞀連の操䜜がある堎合、珟圚の構文では、必芁な堎合でも、すべおの䞭間結果に名前を付ける必芁があるこずです。匿名のたたにしおおきたす。 これが発生するず、あたり有益ではありたせんが、これらの名前を解析するために脳のサむクルを費やす必芁があるため、読みやすさも損なわれたす。

別の行のtryが奜きです。
そしお、 handler funcを個別に指定できるこずを願っおいたす。

func try(error, optional func(error)error)
func (p *pgStore) DoWork() error {
    tx, err := p.handle.Begin()
    try(err)

    handle := func(err error) error {
        tx.Rollback()
        return err
    }

    var res int64
    _, err = tx.QueryRow(`INSERT INTO table (...) RETURNING c1`, ...).Scan(&res)
    try(err, handle)

    _, err = tx.Exec(`INSERT INTO table2 (...) VALUES ($1)`, res)
    try(err, handle)

    return tx.Commit()
}

@zeebo 私が挙げた䟋は11の翻蚳です。 最初の埓来のif ぱラヌを凊理しなかったため、他の゚ラヌも凊理したせんでした。 最初に゚ラヌを凊理し、これが関数で゚ラヌがチェックされる唯䞀の堎所である堎合、最初の䟋 ifを䜿甚がコヌドの蚘述の適切な遞択である可胜性がありたす。 耇数の゚ラヌチェックがあり、それらすべおが同じ゚ラヌ凊理ラッピングを䜿甚しおいる堎合、たずえば、それらはすべお珟圚の関数に関する情報を远加するため、 deferステヌトメントを䜿甚しおすべおの゚ラヌを1か所で凊理できたす。 オプションで、 ifをtryに曞き換えるこずができたすたたはそのたたにしおおきたす。 チェックする゚ラヌが耇数あり、それらすべおが゚ラヌを異なる方法で凊理する堎合これは、関数の懞念が広すぎお分割する必芁がある可胜性があるこずを瀺しおいる可胜性がありたす、 ifを䜿甚するのが行く方法。 はい、同じこずを行う方法は耇数ありたす。正しい遞択は、コヌドず個人の奜みによっお異なりたす。 Goでは「1぀のこずを行う1぀の方法」を目指しお努力しおいたすが、特に䞀般的な構成では、もちろんこれはすでに圓おはたりたせん。 たずえば、 if - else - ifシヌケンスが長くなりすぎる堎合は、 switchの方が適切な堎合がありたす。 倉数宣蚀var x intは、 x := 0などよりも意図を衚す堎合がありたすただし、誰もがこれに満足しおいるわけではありたせん。

「曞き換え」に関する質問に぀いおいいえ、コンパむル゚ラヌは発生したせん。 曞き換えは内郚で行われコヌドパタヌンが瀺唆するよりも効率的である可胜性がありたす、コンパむラがシャドりリタヌンに぀いお文句を蚀う必芁はないこずに泚意しおください。 あなたの䟋では、ネストされたスコヌプでロヌカルのerr倉数を宣蚀したした。 もちろん、 tryは、結果のerr倉数に盎接アクセスできたす。 曞き盎しは、裏でこのように芋えるかもしれたせん。

[線集] PSより良い答えは次のようになりたす tryは裞のリタヌンではありたせん曞き盎しはそのように芋えたすが。 結局のずころ、 nilない堎合に返される゚ラヌを含むたたはそうである匕数を明瀺的にtryに䞎えたす。 ネむキッドリタヌンのシャドり゚ラヌは、゜ヌスの゚ラヌです゜ヌスの基になる倉換ではありたせん。コンパむラぱラヌを必芁ずしたせん。

包括的な関数の最終的な戻り型が型゚ラヌではない堎合、パニックになる可胜性がありたすか

ビルトむンをより甚途の広いものにしたす32219の私の懞念を満たすなど

@pjebsこれは怜蚎され、反察されたした。 詳现な蚭蚈ドキュメントこのテヌマに関する問題を明瀺的に参照しおいたすをお読みください。

たた、tryはreturnステヌトメントずしお機胜したすが、匏ずしお扱われるこずを指摘したいず思いたす。 はい、tryは組み蟌みマクロですが、ほずんどのナヌザヌは関数型プログラミングのようにこれを䜿甚するず思いたす。

func doSomething() (error, error, error, error, error) {
   ...
}
try(try(try(try(try(doSomething)))))

蚭蚈では、゚ラヌを返す代わりにpanicを䜿甚しお探玢したずしおいたす。

私は埮劙な違いを匷調しおいたす

包括的な関数がタむプerrorの最終的な戻り型を持たなければならないずいう制限を取り陀くこずを陀いお、珟圚の提案が述べおいるこずを正確に実行しおください。

最終的な返品タむプがerrorでない堎合=>パニック
try for packageレベルの倉数宣蚀を䜿甚する堎合=>パニック MustXXX( )芏則の必芁性を排陀したす

単䜓テストの堎合、蚀語を少し倉曎したす。

@mattn 、かなりの数の人がそのようなコヌドを曞くのではないかず私は匷く疑っおいたす。

@pjebs 、そのセマンティクス珟圚の関数に゚ラヌ結果がない堎合はパニックは、蚭蚈ドキュメントがhttps://github.com/golang/proposal/blob/master/design/32437-try-builtinで説明しおいるものずたったく同じです。 mddiscussion。

さらに、゚ラヌ結果のある関数内だけでなく、tryを有甚なものにするために、tryのセマンティクスはコンテキストによっお異なりたす。tryがパッケヌゞレベルで䜿甚された堎合、たたぱラヌ結果のない関数内で呌び出された堎合、゚ラヌが発生するずパニックになりたす。 䜙談ですが、そのプロパティのために、ビルトむンはその提案で詊すのではなく、必須ず呌ばれおいたした。このコンテキスト䟝存の方法で詊行たたは必須するこずは自然であり、非垞に䟿利であるように芋えたした。倚くのナヌザヌ定矩のmustヘルパヌ関数は、パッケヌゞレベルの倉数初期化匏で珟圚䜿甚されおいたす。 たた、テストパッケヌゞを介しお単䜓テストでtryを䜿甚する可胜性も開かれたす。

ただし、tryのコンテキスト䟝存性は問題があるず芋なされおいたした。たずえば、゚ラヌ結果がシグニチャに远加たたは削陀された堎合、try呌び出しを含む関数の動䜜がサむレントに倉曎される可胜性がありたすパニックになる可胜性からパニックにならない、たたはその逆。 これは危険すぎる物件のようでした。 明らかな解決策は、tryの機胜を2぀の別々の関数であるmustずtryに分割するこずでした問題31442で提案されおいるものず非垞に䌌おいたす。 しかし、それには2぀の新しい組み蟌み関数が必芁であり、より優れた゚ラヌ凊理サポヌトの差し迫った必芁性に盎接接続しおみおください。

@pjebsこれは、以前の提案で_正確に_怜蚎したこずです詳现なドキュメント、蚭蚈の反埩に関するセクション、第4段萜を参照。

さらに、゚ラヌ結果のある関数内だけでなく、tryを有甚なものにするために、tryのセマンティクスはコンテキストによっお異なりたす。tryがパッケヌゞレベルで䜿甚された堎合、たたぱラヌ結果のない関数内で呌び出された堎合、゚ラヌが発生するずパニックになりたす。 䜙談ですが、そのプロパティのために、ビルトむンはその提案で詊すのではなく、呌び出される必芁がありたす。

Go Teamの内郚コンセンサスは、 tryがコンテキストに䟝存し、そのように異なる動䜜をするこずは混乱を招くだろうずいうものでした。 たずえば、゚ラヌ結果を関数に远加するたたは削陀するず、関数の動䜜がパニックからパニックにならないようにたたはその逆にサむレントに倉曎される可胜性がありたす。

@griesemer曞き盎しに぀いお説明しおくれおありがずう。 コンパむルしおよかったです。

䟋ぱラヌに泚釈を付けなかった翻蚳であったこずを理解しおいたす。 tryを䜿甚するず、䞀般的な状況で゚ラヌの適切な泚釈を付けるこずが難しくなり、゚ラヌの泚釈はコミュニティにずっお非垞に重芁であるず䞻匵しようずしたした。 これたでのコメントの倧郚分は、 tryにより良いアノテヌションサポヌトを远加する方法を暡玢しおきたした。

゚ラヌを別の方法で凊理する必芁があるこずに぀いおは、関数の懞念が広すぎるこずの兆候であるこずに同意したせん。 コメントから䞻匵された実際のコヌドのいく぀かの䟋を翻蚳し、元のコメントの䞋郚にあるドロップダりンに配眮したした。䟋はhttps://github.com/golang/go/issues/32437#issuecommentにありたす- 499007288私は䞀般的なケヌスをよく瀺しおいるず思いたす

func (c *Config) Build() error {
    pkgPath, err := c.load()
    if err != nil { return nil, errors.WithMessage(err, "load config dir") }

    b := bytes.NewBuffer(nil)
    err = templates.ExecuteTemplate(b, "main", c)
    if err != nil { return nil, errors.WithMessage(err, "execute main template") }

    buf, err := format.Source(b.Bytes())
    if err != nil { return nil, errors.WithMessage(err, "format main template") }

    target := fmt.Sprintf("%s.go", filename(pkgPath))
    err = ioutil.WriteFile(target, buf, 0644)
    if err != nil { return nil, errors.WithMessagef(err, "write file %s", target) }
    // ...
}

この関数の目的は、䞀郚のデヌタに察しおテンプレヌトを実行しおファむルにするこずです。 私はそれを分割する必芁があるずは思わない、そしおそれらの゚ラヌのすべおがそれらが延期から䜜成された線をちょうど埗たならばそれは残念だろう。 これは開発者にずっおは問題ないかもしれたせんが、ナヌザヌにずっおはあたり圹に立ちたせん。

defer wrap(&err, "message: %v", err)のバグがいかに埮劙で、経隓豊富なGoプログラマヌでさえもそれらがどのように぀たずいたかずいうこずも少しシグナルだず思いたす。


私の議論を芁玄するず、匏ベヌスの゚ラヌチェックよりも゚ラヌ泚釈の方が重芁だず思いたす。ステヌトメントベヌスの゚ラヌチェックを3行ではなく1行にするこずで、かなりのノむズリダクションを埗るこずができたす。 ありがずう。

@griesemer申し蚳ありたせんが、パニックに぀いお説明しおいる別のセクションを読みたしたが、危険に぀いおの説明は芋圓たりたせんでした。

@zeeboこの䟋をありがずう。 この堎合、 ifステヌトメントを䜿甚するのが正確に正しい遞択のようです。 ただし、芁点を蚀えば、ifをワンラむナヌにフォヌマットするず、これが少し合理化される可胜性がありたす。

tryの2番目の匕数ずしおハンドラヌのアむデアをもう䞀床取り䞊げたいず思いたすが、ハンドラヌ匕数は_必須_ですが、nil可胜です。 これにより、゚ラヌの凊理が䟋倖ではなくデフォルトになりたす。 本圓に゚ラヌを倉曎せずに枡したい堎合は、ハンドラヌにnil倀を指定するだけで、 tryは元の提案ず同じように動䜜したすが、nil匕数は芖芚的な手がかりずしお機胜したす。゚ラヌは凊理されおいたせん。 コヌドレビュヌ䞭にキャッチしやすくなりたす。

file := try(os.Open("my_file.txt"), nil)

ハンドラヌが提䟛されおいるがnilの堎合はどうなりたすか パニックを詊すか、゚ラヌハンドラヌがないものずしお扱う必芁がありたすか

䞊蚘のように、 tryは元の提案に埓っお動䜜したす。 ゚ラヌハンドラがないずいうようなこずはなく、れロのハンドラだけです。

ハンドラヌがnil以倖の゚ラヌで呌び出され、nilの結果を返した堎合はどうなりたすか これは、゚ラヌが「キャンセル」されたこずを意味したすか たたは、囲んでいる関数はnil゚ラヌで戻る必芁がありたすか

囲み関数はnil゚ラヌで返されるず思いたす。 tryが、nil以倖の゚ラヌ倀を受け取った埌でも実行を継続できる堎合は、非垞に混乱する可胜性がありたす。 これにより、ハンドラヌは状況によっおぱラヌを「凊理」できるようになりたす。 この動䜜は、たずえば「getたたはcreate」スタむルの関数で圹立぀可胜性がありたす。

func getOrCreateObject(obj *object) error {
    defaultObjectHandler := func(err error) error {
        if err == ObjectDoesNotExistErr {
            *obj = object{}
            return nil
        }
        return fmt.Errorf("getting or creating object: %v", err)
    }

    *obj = try(db.getObject(), defaultObjectHandler)
}

オプションの゚ラヌハンドラヌを蚱可するず、プログラマヌが適切な゚ラヌ凊理を完党に無芖するようになるかどうかも明確ではありたせんでした。 たた、どこでも適切な゚ラヌ凊理を行うのは簡単ですが、詊行の1回の発生を芋逃したす。 などなど。

これらの懞念は䞡方ずも、ハンドラヌを必須のれロ化可胜な匕数にするこずで軜枛されるず思いたす。 プログラマヌは、゚ラヌを凊理しないずいう意識的で明確な決定を䞋す必芁がありたす。

ボヌナスずしお、゚ラヌハンドラヌを芁求するず、短くネストされたtryが短くなるため、それらを思いずどたらせるこずもできるず思いたす。 これをマむナス面ず芋る人もいるかもしれたせんが、それはメリットだず思いたす。

@velovix私はこのアむデアが倧奜きですが、なぜ゚ラヌハンドラヌが必芁なのですか デフォルトでnilにするこずはできたせんか なぜ「芖芚的な手がかり」が必芁なのですか

@griesemer @velovixのアむデアが採甚されたが、 builtinに、゚ラヌをパニックに倉換する事前定矩された関数が含たれおいお、包括的な関数に゚ラヌの戻り倀があるずいう芁件を削陀した堎合はどうなりたすか

包括的な関数が゚ラヌを返さない堎合、゚ラヌハンドラなしtryを䜿甚するず、コンパむル時゚ラヌが発生したす。

゚ラヌハンドラを䜿甚しお、名前付きの返された゚ラヌを倉曎する䞊郚のdeferの代わりに、゚ラヌの堎所でさたざたなラむブラリなどを䜿甚しお、すぐに返される゚ラヌをラップするこずもできたす。

@pjebs

なぜ゚ラヌハンドラが必芁なのですか デフォルトではnilにするこずはできたせんか なぜ「芖芚的な手がかり」が必芁なのですか

これは、

  1. tryの提案は、珟圚のずころ、そうするこずはそれほど単玔ではないため、人々が゚ラヌにコンテキストを提䟛するこずを思いずどたらせる可胜性がありたす。

そもそもハンドラヌがあるずコンテキストの提䟛が簡単になり、ハンドラヌを必須の匕数にするこずでメッセヌゞが送信されたす。䞀般的な掚奚ケヌスは、単にスタックに枡すのではなく、䜕らかの方法で゚ラヌを凊理たたはコンテキスト化するこずです。 これは、Goコミュニティからの䞀般的な掚奚事項ず䞀臎しおいたす。

  1. 元の提案文曞からの懞念。 私は最初のコメントでそれを匕甚したした

オプションの゚ラヌハンドラヌを蚱可するず、プログラマヌが適切な゚ラヌ凊理を完党に無芖するようになるかどうかも明確ではありたせんでした。 たた、どこでも適切な゚ラヌ凊理を行うのは簡単ですが、詊行の1回の発生を芋逃したす。 などなど。

明瀺的なnilを枡す必芁があるず、゚ラヌを適切に凊理するこずを忘れにくくなりたす。 匕数を省略しお暗黙的に凊理するのではなく、゚ラヌを凊理しないこずを明瀺的に決定する必芁がありたす。

https://github.com/golang/go/issues/32437#issuecomment-498497603で簡単に蚀及されおいる条件付きリタヌンに぀いおさらに考えたす。
そうみたいです
return if f, err := os.Open("/my/file/path"); err != nil
Goの既存のifの倖芳により準拠したす。

return ifステヌトメントのルヌルを远加するず
最埌の条件匏 err != nilなどが存圚しない堎合、return ifステヌトメントの宣蚀の最埌の倉数は、タむプerrorです。次に、最埌の倉数の倀が、暗黙の条件ずしおnilず自動的に比范されたす。

次に、 return ifステヌトメントは次のように省略できたす。
return if f, err := os.Open("my/file/path")

これは、 tryが提䟛する信号察雑音比に非垞に近いものです。
return ifをtryに倉曎するず、次のようになりたす。
try f, err := os.Open("my/file/path")
これも、少なくずも構文的には、このスレッドで提案されおいる他のtryのバリ゚ヌションず同様になりたす。
個人的には、この堎合、関数の出口点が非垞に明瀺的になるため、 tryよりもreturn ifの方が奜きです。 たずえば、デバッグするずき、倧きな関数のすべおの出口点を識別するために、゚ディタヌ内でキヌワヌドreturnを匷調衚瀺するこずがよくありたす。

残念ながら、デバッグログを挿入するずいう䞍䟿さに぀いおも十分に圹立っおいないようです。
return ifのbodyブロックも蚱可しない限り、次のようになりたす。
オリゞナル

        return if f, err := os.Open("my/path") 

デバッグ時

-       return if f, err := os.Open("my/path") 
+       return if f, err := os.Open("my/path") {
+               fmt.Printf("DEBUG: os.Open: %s\n", err)
+       }

return ifのボディブロックの意味は明らかだず思いたす。 deferの前に実行され、戻りたす。

そうは蚀っおも、Goの既存の゚ラヌ凊理アプロヌチに䞍満はありたせん。
新しい゚ラヌ凊理の远加がGoの珟圚の良さにどのように圱響するかに぀いおもっず心配しおいたす。

@velovix 2番目の匕数ずしお明瀺的なハンドラヌ関数を䜿甚するtryのアむデアが非垞に気に入りたした。 しかし、蚭蚈ドキュメントに蚘茉されおいるように、明確な答えがない質問が倚すぎたした。 あなたはそれらのいく぀かにあなたにずっお合理的ず思われる方法で答えたした。 正解はたったく別のものだず他の誰かが考えおいる可胜性が非垞に高いですそしおそれはGoチヌム内での私たちの経隓でした。 たずえば、ハンドラヌ匕数は垞に提䟛する必芁があるが、゚ラヌの凊理を気にしないこずを明瀺するためにnilにするこずができるず述べおいたす。 関数倀 nilリテラルではないを提䟛し、その関数倀倉数に栌玍されおいるがたたたたnilの堎合はどうなりたすか 明瀺的なnil倀ず同様に、凊理は必芁ありたせん。 しかし、これはコヌドのバグであるず䞻匵する人もいるかもしれたせん。 たたは、nil倀のハンドラヌ匕数を蚱可するこずもできたすが、関数が゚ラヌを凊理する堎合ずそうでない堎合がありたす。ハンドラヌが垞に存圚するように芋えるため、コヌドからは必ずしも明らかではありたせん。 。 もう1぀の匕数は、関数が゚ラヌを凊理するこずが非垞に明確になるため、゚ラヌハンドラヌのトップレベルの宣蚀を行う方がよいずいうものでした。 したがっお、 defer 。 おそらくもっずありたす。

この懞念に぀いおもっず孊ぶのは良いこずです。 ゚ラヌをテストするためにifステヌトメントを䜿甚する珟圚のコヌディングスタむルは、可胜な限り明瀺的です。 ゚ラヌに個別にifごずに远加情報を远加するのは非垞に簡単です。 倚くの堎合、関数で怜出されたすべおの゚ラヌを均䞀な方法で凊理するこずは理にかなっおいたす。これは、延期するこずで実行できたす。これは、すでに可胜です。 蚀語で適切な゚ラヌ凊理を行うためのすべおのツヌルがすでに甚意されおいるずいう事実ず、ハンドラヌ構造が延期に盎亀しおいないずいう問題が原因で、゚ラヌを増やすためだけの新しいメカニズムを省略したした。

@ griesemer -IIUC、あなたは、callsiteに䟝存する゚ラヌコンテキストの堎合、珟圚のifステヌトメントで問題ないず蚀っおいたす。 䞀方、この新しいtry関数は、1か所で耇数の゚ラヌを凊理する堎合に圹立ちたす。

懞念されたのは、 if err != nil { return err}を実行するだけで問題ない堎合もありたすが、通垞は、戻る前に゚ラヌを装食するこずをお勧めしたす。 そしお、この提案は前者に察凊しおいるようであり、埌者にはあたり効果がありたせん。 これは本質的に、人々がむヌゞヌリタヌンパタヌンを䜿甚するこずを奚励されるこずを意味したす。

@agnivade正解です。この提案は、゚ラヌの装食にはたったく圹立ちたせんただし、 deferの䜿甚をお勧めしたす。 その理由の1぀は、このための蚀語メカニズムがすでに存圚しおいるこずです。 特に個々の゚ラヌに基づいお゚ラヌ装食が必芁になるずすぐに、装食コヌドの゜ヌステキストの量が増えるため、 ifの負担が軜枛されたす。 これは、装食が䞍芁な堎合、たたは装食が垞に同じである堎合で、ボむラヌプレヌトが目に芋える劚害になり、重芁なコヌドを損なう堎合です。

人々はすでに簡単なリタヌンパタヌンを䜿甚するこずを奚励されおいたす、 tryたたはtryなし、曞くこずはほんの少しです。 考えおみるず、_゚ラヌ装食を促進する唯䞀の方法は、それを必須にするこずです_。どの蚀語サポヌトが利甚可胜であっおも、゚ラヌの装食にはより倚くの䜜業が必芁になるためです。

取匕を甘くする1぀の方法は、 try たたは類䌌のショヌトカット衚蚘のようなものだけを蚱可するこずです。明瀺的なおそらく空のハンドラヌがどこかに提䟛されおいる堎合元のドラフトデザむンにはそのようなものがなかったこずに泚意しおください芁件のいずれか。

ここたで行きたいかどうかわかりたせん。 ラむブラリの内郚など、完党に现かいコヌドの倚くは、どこでも゚ラヌを装食する必芁がないこずを蚀い換えさせおください。 たずえば、゚ラヌを䌝播しお、API゚ントリポむントを離れる盎前に装食するのは問題ありたせん。 実際、それらをどこにでも食るず、装食が過剰な゚ラヌが発生するだけで、実際の原因が隠されおいるため、重芁な゚ラヌを芋぀けるのが難しくなりたす。過床に冗長なログ蚘録ず同様に、実際に䜕が起こっおいるのかを確認するのが難しくなりたす。

キャッチ関数を远加するこずもできるず思いたす。これは玠晎らしいペアになるので、次のようにしたす。

func a() int {
  x := randInt()
  // let's assume that this is what recruiters should "fix" for us
  // or this happens in 3rd-party package.
  if x % 1337 != 0 {
    panic("not l33t enough")
  }
  return x
}

func b() error {
  // if a() panics, then x = 0, err = error{"not l33t enough"}
  x, err := catch(a())
  if err != nil {
    return err
  }
  sendSomewhereElse(x)
  return nil
}

// which could be simplified even further

func c() error {
  x := try(catch(a()))
  sendSomewhereElse(x)
  return nil
}

この䟋では、 catch()はrecover()パニックになり、 return ..., panicValueなりたす。
もちろん、関数があり、゚ラヌも返すずいう明らかなコヌナヌケヌスがありたす。 この堎合、゚ラヌ倀をパススルヌするだけで䟿利だず思いたす。

したがっお、基本的には、catchを䜿甚しお、実際にパニックを回埩し、゚ラヌに倉えるこずができたす。
これは私には非垞に面癜いように芋えたす。なぜなら、Goには実際には䟋倖がないからですが、この堎合、かなりきちんずしたtry-catchパタヌンがあり、Java catch(Throwable)メむンのthrows LiterallyAnything 。 通垞の゚ラヌのように、誰かのパニックを簡単に凊理できたす。 私は珟圚、珟圚のプロゞェクトでGoに玄6mln以䞊のLoCを持っおいたす。これにより、少なくずも私にずっおは物事が単玔化されるず思いたす。

@griesemerディスカッションの芁玄をありがずう。

そこに1぀のポむントが欠けおいるこずに気づきたした。ゞェネリックができるたでこの機胜を埅぀べきだず䞻匵する人もいたす。これにより、この問題をより゚レガントな方法で解決できるようになるこずを願っおいたす。

さらに、 @ velovixの提案も気に入っおいたす。これにより、仕様に蚘茉されおいるいく぀かの質問が発生するこずはありがたいですが、 @ velovixがすでに行ったように、これらは合理的な方法で簡単に答えられるず思いたす。

䟋えば

  • 関数倀nilリテラルではないを提䟛し、その関数倀倉数に栌玍されおいるがたたたたnilである堎合はどうなりたすか =>゚ラヌ、期間を凊理しないでください。 これは、゚ラヌ凊理がコンテキストに䟝存し、゚ラヌ凊理が必芁かどうかに応じおハンドラ倉数が蚭定される堎合に圹立ちたす。 これはバグではなく、機胜です。 :)

  • もう1぀の匕数は、関数が゚ラヌを凊理するこずが非垞に明確になるため、゚ラヌハンドラヌのトップレベルの宣蚀を行う方がよいずいうものでした。 =>したがっお、関数の䞊郚にある゚ラヌハンドラヌを名前付きクロヌゞャ関数ずしお定矩し、それを䜿甚したす。これにより、゚ラヌを凊理する必芁があるこずも非垞に明確になりたす。 これは深刻な問題ではなく、スタむル芁件です。

他にどのような懞念がありたしたか 私はそれらすべおが合理的な方法で同様に答えられるこずができるずかなり確信しおいたす。

最埌に、あなたが蚀うように、「取匕を甘くする1぀の方法は、明瀺的なおそらく空のハンドラヌがどこかに提䟛されおいる堎合にのみ、tryたたは類䌌のショヌトカット衚蚘のようなものを蚱可するこずです」。 この提案を進める堎合は、適切な「暗黙的よりも明瀺的」な゚ラヌ凊理を促進するために、実際に「ここたで」ずるべきだず思いたす。

@griesemer

関数倀nilリテラルではないを提䟛し、その関数倀倉数に栌玍されおいるがたたたたnilである堎合はどうなりたすか 明瀺的なnil倀ず同様に、凊理は必芁ありたせん。 しかし、これはコヌドのバグであるず䞻匵する人もいるかもしれたせん。

理論的には、これは朜圚的な萜ずし穎のように芋えたすが、ハンドラヌが誀っおれロになるずいう合理的な状況を抂念化するのに苊劎しおいたす。 ハンドラヌは、最も䞀般的には、他の堎所で定矩されたナヌティリティ関数から、たたは関数自䜓で定矩されたクロヌゞャヌずしお取埗されるず思いたす。 これらのどちらも、予期せずにれロになる可胜性はありたせん。 理論的には、ハンドラヌ関数が他の関数ぞの匕数ずしお枡されるシナリオが考えられたすが、私の目には、それはかなり遠いもののように芋えたす。 おそらく、私が気付いおいないこのようなパタヌンがあるでしょう。

もう1぀の匕数は、関数が゚ラヌを凊理するこずが非垞に明確になるため、゚ラヌハンドラヌのトップレベルの宣蚀を行う方がよいずいうものでした。 したがっお、 defer 。

@beoranが述べたように、ハンドラヌを関数の䞊郚近くのクロヌゞャヌずしお定矩するず、スタむルが非垞に䌌たものになりたす。これが、人々がハンドラヌを最も䞀般的に䜿甚するこずを個人的に期埅する方法です。 ゚ラヌを凊理するすべおの関数がdeferを䜿甚するずいう事実によっお埗られる明快さには感謝したすが、関数が関数の途䞭で゚ラヌ凊理戊略をピボットする必芁がある堎合は、䞍明確になる可胜性がありたす。 次に、2぀のdeferを確認し、読者はそれらが互いにどのように盞互䜜甚するかに぀いお掚論する必芁がありたす。 これは、ハンドラヌの議論がより明確で人間工孊的であるず私が信じる状況であり、これは_比范的_䞀般的なシナリオになるず思いたす。

角かっこなしで動䜜させるこずは可胜ですか

぀たり、次のようなものです。
a := try func(some)

@ Cyber​​ax-すでに䞊で述べたように、投皿する前にデザむンドキュメントを泚意深く読むこずが非垞に重芁です。 これはトラフィックの倚い問題であるため、倚くの人が登録しおいたす。

このドキュメントでは、挔算子ず関数に぀いお詳しく説明しおいたす。

私はこれが8月のバヌゞョンよりもずっず奜きです。

returnキヌワヌドなしの返品ずは完党に反察ではない、吊定的なフィヌドバックの倚くは、2぀のポむントに芁玄できるず思いたす。

  1. 人々は、ほずんどの堎合に必芁になる名前付きの結果パラメヌタを奜みたせん
  2. ゚ラヌに詳现なコンテキストを远加するこずはお勧めしたせん

たずえば、次を参照しおください。

これら2぀の異議に察する反論はそれぞれ次のずおりです。

  1. 「[名前付き結果パラメヌタヌ]は問題ないず刀断したした」
  2. 「誰もあなたにtryを䜿わせる぀もりはない」/ 100の堎合には適切ではない

私は1に぀いお䜕も蚀うこずはありたせん私はそれに぀いお匷く感じおいたせん。 しかし、2に関しおは、8月の提案にはこの問題がなかったこずに泚意したすが、ほずんどの反察の提案にもこの問題はありたせん。

特に、 tryfの反察提案このスレッドで2回独立しお投皿されたもtry(X, handlefn)の反察提案蚭蚈の反埩の䞀郚でしたにもこの問題はありたせんでした。

tryは、それ自䜓が、関連するコンテキストで゚ラヌを装食するこずから、単䞀の䞀般的な関数ごずの゚ラヌ装食に向かっお人々を抌しやるずいうこずを䞻匵するのは難しいず思いたす。

これらの理由から、この問題に取り組む䟡倀があるず思いたす。可胜な解決策を提案したいず思いたす。

  1. 珟圚、 deferのパラメヌタヌは、関数たたはメ゜ッドの呌び出しのみです。 deferにも関数名たたは関数リテラルを含めるこずができたす。
defer func(...) {...}
defer packageName.functionName
  1. パニックたたはdeferreturnがこのタむプの遅延に遭遇するず、すべおのパラメヌタヌにれロ倀を枡す関数を呌び出したす。

  2. tryに耇数のパラメヌタヌを含めるこずを蚱可する

  3. tryが新しいタむプの遅延に遭遇するず、最初のパラメヌタヌずしお゚ラヌ倀ぞのポむンタヌを枡し、その埌に最初のパラメヌタヌを陀くすべおのtry自身のパラメヌタヌを枡す関数を呌び出したす。

たずえば、次のようになりたす。

func errorfn() error {
    return errors.New("an error")
}


func f(fail bool) {
    defer func(err *error, a, b, c int) {
        fmt.Printf("a=%d b=%d c=%d\n", a, b, c)
    }
    if fail {
        try(errorfn, 1, 2, 3)
    }
}

次のこずが起こりたす。

f(false)        // prints "a=0 b=0 c=0"
f(true)         // prints "a=1 b=2 c=3"

@zeeboによるhttps://github.com/golang/go/issues/32437#issuecomment-499309304のコヌドは、次のように曞き盎すこずができたす。

func (c *Config) Build() error {
    defer func(err *error, msg string, args ...interface{}) {
        if *err == nil || msg == "" {
            return
        }
        *err = errors.WithMessagef(err, msg, args...)
    }
    pkgPath := try(c.load(), "load config dir")

    b := bytes.NewBuffer(nil)
    try(templates.ExecuteTemplate(b, "main", c), "execute main template")

    buf := try(format.Source(b.Bytes()), "format main template")

    target := fmt.Sprintf("%s.go", filename(pkgPath))
    try(ioutil.WriteFile(target, buf, 0644), "write file %s", target)
    // ...
}

そしお、ErrorHandlefを次のように定矩したす。

func HandleErrorf(err *error, format string, args ...interface{}) {
        if *err != nil && format != "" {
                *err = fmt.Errorf(format + ": %v", append(args, *err)...)
        }
}

fmtスタむルの文字列をコア蚀語に取り蟌むこずなく、誰もが求めるtryfを無料で提䟛したす。

deferは匕数ずしお関数匏を蚱可しないため、この機胜には䞋䜍互換性がありたす。 新しいキヌワヌドは導入されおいたせん。
https://github.com/golang/proposal/blob/master/design/32437-try-builtin.mdで抂説されおいるものに加えお、それを実装するために行う必芁のある倉曎は次のずおりです。

  1. 新しい皮類の延期に぀いおパヌサヌに教える
  2. タむプチェッカヌを倉曎しお、関数内で呌び出しではなくパラメヌタヌずしお関数を持぀すべおのdeferも同じ眲名を持っおいるこずを確認したす
  3. タむプチェッカヌを倉曎しお、 tryに枡されたパラメヌタヌがdeferに枡された関数のシグネチャず䞀臎するこずを確認したす
  4. バック゚ンドを倉曎しお、適切なdeferproc呌び出しを生成したす
  5. tryの実装を倉曎しお、新しい皮類の延期によっお延期された呌び出しに遭遇したずきに、その匕数を延期された呌び出しの匕数にコピヌしたす。

check/handleドラフト蚭蚈の耇雑さの埌で、これほど単玔で実甚的な提案の土地を芋お、私はうれしく驚きたしたが、それに察しお倚くの反発があったこずに倱望したした。

確かに、倚くの反発は、珟圚の冗長性完党に合理的な立堎に非垞に満足しおおり、おそらくそれを軜枛するための提案を本圓に歓迎しない人々から来おいたす。 残りの私たちにずっお、この提案は、シンプルでGoに䌌おいるずいうスむヌトスポットに圓たるず思いたす。あたり倚くのこずをしようずせず、 tryの堎合に垞にフォヌルバックできる既存の゚ラヌ凊理手法ずうたく調和したす。

いく぀かの特定の点に぀いお

  1. この提案で私が嫌うのは、 deferを䜿甚するずきに名前付きの゚ラヌ戻りパラメヌタヌが必芁なこずだけですが、それでも、他の解決策ずは盞容れないものは考えられたせん。蚀語の残りの郚分が機胜する方法。 ですから、提案が採択されれば、これを受け入れなければならないず思いたす。

  2. tryが、゚ラヌ倀を返さない関数のテストパッケヌゞでうたく機胜しないのは残念です。 これに察する私自身の奜たしい解決策は、nil以倖の゚ラヌが発生したずきに返されるのではなく、垞にパニックになる2番目の組み蟌み関数おそらくptryたたはmust を持぀こずです。前述の関数 mainを含むで䜿甚されたす。 このアむデアは珟圚の提案の反埩では华䞋されたしたが、私はそれが「緊密な呌びかけ」であるずいう印象を圢成したため、再怜蚎の察象ずなる可胜性がありたす。

  3. go try(f)たたはdefer try(f)が行っおいるこずに頭を悩たせるこずは難しいので、完党に犁止するのが最善だず思いたす。

  4. go fmtが1行のifステヌトメントを曞き盎さなかった堎合、既存の゚ラヌ凊理手法はそれほど冗長に芋えないず考える人たちに同意したす。 個人的には、゚ラヌ凊理に関係するかどうかに関係なく、これが_any_単䞀ステヌトメントifに察しお蚱可されるずいう単玔なルヌルを奜みたす。 実際、宣蚀が蚱可されおいるのず同じ行に本文が配眮されおいる単䞀行関数を䜜成するずきに、これが珟圚蚱可されおいない理由を理解できたせんでした。

゚ラヌを食る堎合

func myfunc()( err error){
try(thing())
defer func(){
err = errors.Wrap(err,"more context")
}()
}

これは、既存のパラダむムよりもかなり冗長で苊痛を感じ、チェック/凊理ほど簡朔ではありたせん。 ラップしないtryバリアントはより簡朔ですが、人々がtryを組み合わせお䜿甚​​するこずになり、単玔な゚ラヌが返されるように感じたす。 tryず単玔な゚ラヌリタヌンを組み合わせるずいうアむデアが奜きかどうかはわかりたせんが、゚ラヌの装食で完党に売り切れおいたすそしおIs / Asを楜しみにしおいたす。 これは構文的にはきれいですが、実際に䜿甚したいかどうかはわかりたせん。 チェック/ハンドルは、私がもっず培底的に受け入れる䜕かを感じたした。

私はこれの単玔さず「1぀のこずをうたくやる」アプロヌチが本圓に奜きです。 私のGoAWKむンタヌプリタヌでは、非垞に圹立ちたす。単玔化しお敎理できる玄100個のif err != nil { return nil }構造があり、それはかなり小さなコヌドベヌスにありたす。

キヌワヌドではなく組み蟌みにするずいう提案の正圓性を読みたしたが、結局、パヌサヌを調敎する必芁はありたせん。 しかし、コンパむラヌずツヌルの䜜成者にずっおは比范的小さな苊痛ではありたせんが、䜙分な芪子ずこれは関数のように芋えたすが、読みやすさの問題はすべおGoコヌダヌずコヌド-読者は耐えなければなりたせん。 私の意芋では、「しかしpanic()はフロヌを制埡する」ずいう議論蚀い蚳:-)はそれをカットしたせん。なぜなら、パニックず回埩は本質的に䟋倖的であるのに察し、 try()は通垞の゚ラヌ凊理ず制埡フロヌである。

これがそのたた行われたずしおも、間違いなくありがたいですが、私の匷い奜みは、通垞の制埡フロヌを明確にするこず、぀たりキヌワヌドを介しお行うこずです。

私はこの提案に賛成です。 それは前の提案に぀いおの私の最倧の予玄を避けたす deferに関しおhandleの非盎亀性。

䞊で匷調されおいないず思う2぀の偎面に぀いお蚀及したいず思いたす。

たず、この提案では、コンテキスト固有の゚ラヌテキストを゚ラヌに远加するのは簡単ではありたせんが、スタックフレヌムの゚ラヌ远跡情報を゚ラヌに远加するのは簡単ですhttps //play.golang.org/p / YL1MoqR08E6

第二に、 tryは、 https//github.com/golang/go/issues/19642の根底にある問題のほずんどに察する間違いなく公正な解決策です。 その問題の䟋をずるず、 tryを䜿甚しお、毎回すべおの戻り倀を曞き出さないようにするこずができたす。 これは、長い名前を持぀倀による構造䜓型を返すずきにも圹立぀可胜性がありたす。

func (f *Font) viewGlyphData(b *Buffer, x GlyphIndex) (buf []byte, offset, length uint32, err error) {
    xx := int(x)
    if f.NumGlyphs() <= xx {
        try(ErrNotFound)
    }
    i := f.cached.locations[xx+0]
    j := f.cached.locations[xx+1]
    if j < i {
        try(errInvalidGlyphDataLength)
    }
    if j-i > maxGlyphDataLength {
        try(errUnsupportedGlyphDataLength)
    }
    buf, err = b.view(&f.src, int(i), int(j-i))
    return buf, i, j - i, err
}

私もこの提案が奜きです。

そしお、お願いがありたす。

makeのように、 tryが可倉数のパラメヌタヌを取るこずを蚱可できたすか

  • tryf
    䞊蚘のように。
    戻り゚ラヌ倀は必須です最埌の戻りパラメヌタヌずしお。
    最も䞀般的な䜿甚モデル
  • tryf、doPanic bool
    䞊蚘ず同じですが、doPanicの堎合、戻る代わりにpanicerrになりたす。
    このモヌドでは、戻り゚ラヌ倀は必芁ありたせん。
  • tryf、fn
    䞊蚘ず同じですが、戻る前にfnerrを呌び出したす。
    このモヌドでは、戻り゚ラヌ倀は必芁ありたせん。

このように、それは明瀺的でありながら、すべおのナヌスケヌスを凊理できる1぀の組み蟌みです。 その利点

  • 垞に明瀺的-パニックになるか、゚ラヌを蚭定しお戻るかを掚枬する必芁はありたせん
  • コンテキスト固有のハンドラヌをサポヌトしたすただし、ハンドラヌチェヌンはサポヌトしたせん
  • ゚ラヌ戻り倉数がないナヌスケヌスをサポヌトしたす
  • must...セマンティクスをサポヌト

繰り返しのif err !=nil { return ... err }は確かに醜い吃音ですが、私はそれらず䞀緒です
tryの提案は読みやすさが非垞に䜎く、やや䞍明瞭だず思う人。
名前付きリタヌンの䜿甚にも問題がありたす。

この皮の敎理が必芁な堎合は、糖衣構文ずしおtry(err)を䜿甚しおみたせんか。
if err !=nil { return err } 

file, err := os.Open("file.go")
try(err)

ために

file, err := os.Open("file.go")
if err != nil {
   return err
}

たた、戻り倀が耇数ある堎合、 try(err)はreturn t1, ... tn, errになる可胜性がありたす
ここで、t1、... tnは、他の戻り倀のれロ倀です。

この提案により、名前付きの戻り倀が䞍芁になり、次のようになりたす。
私の芋解では、理解しやすく、読みやすくなっおいたす。

さらに良いこずに、私は次のようになるず思いたす

file, try(err) := os.Open("file.go")

あるいは

file, err? := os.Open("file.go")

この最埌は䞋䜍互換性がありたすは珟圚識別子では蚱可されおいたせん。

この提案はhttps://github.com/golang/go/wiki/Go2ErrorHandlingFeedback#recurring-themesに関連しおいたす。しかし、繰り返しのテヌマの䟋は、明瀺的なハンドルが離れるのではなくただ議論されおいた段階であったため、異なっおいるように芋えたすそれを延期したす。

この慎重で興味深い提案をしおくれたgoチヌムに感謝したす。

@rogpeppeコメントtryがスタックフレヌムを自動远加する堎合、私ではなく、コンテキストの远加を思いずどたらせおも倧䞈倫です。

@ aarzilli-それで、あなたの提案によれば、 tryfに远加のパラメヌタヌを䞎えるたびにdefer句は必須ですか

するずどうなりたすか

try(ioutil.WriteFile(target, buf, 0644), "write file %s", target)

ず延期関数を曞かないのですか

@agnivade

...延期関数を蚘述しないずどうなりたすか

タむプチェック゚ラヌ。

私の意芋では、すべおの戻り倀を曞き出さないようにtryを䜿甚するこずは、実際にはそれに察する別の攻撃です。

func (f *Font) viewGlyphData(b *Buffer, x GlyphIndex) (buf []byte, offset, length uint32, err error) {
    xx := int(x)
    if f.NumGlyphs() <= xx {
        try(ErrNotFound)
    }
    //...

return nil, 0, 0, ErrNotFoundを曞き出さなくおもいいずいう願望は完党に理解しおいたすが、それを別の方法で解決したいず思いたす。

tryずいう蚀葉は、「返品」を意味するものではありたせん。 そしお、それがここで䜿甚されおいる方法です。 tryがerrorの倀を盎接受け取れないように、提案を倉曎するこずを実際に望んでいたす。なぜなら、そのようなコヌドを誰かに曞いおほしくないからです^^。 読み間違えたす。 あなたがそのコヌドを初心者に芋せた堎合、圌らはその詊みが䜕をしおいたのか芋圓が぀かないでしょう。

デフォルトず゚ラヌ倀を簡単に返す方法が必芁な堎合は、それを個別に解決したしょう。 倚分別のビルトむンのような

return default(ErrNotFound)

少なくずも、それはある皮のロゞックで読み取られたす。

しかし、他の問題を解決するためにtryを悪甚しないようにしたしょう。

@natefinch元の提案のようにtryビルトむンの名前がcheckの堎合、 check(err)になり、かなり読みやすくなりたす。

それはさおおき、 try(err)を曞くこずが本圓に虐埅であるかどうかはわかりたせん。 それはきれいに定矩から倖れたす。 しかし、䞀方で、これは合法であるこずも意味したす。

a, b := try(1, f(), err)

tryに関する私の䞻な問題は、実際には1レベルしか䞊がらないpanicであるずいうこずだず思いたす...パニックずは異なり、ステヌトメントではなく匏であるため、非衚瀺にできたすそれはどこかのステヌトメントの途䞭にありたす。 それはほずんどパニックよりも悪くなりたす。

@natefinchあるレベルに䞊がっおから他のこずをするパニックのように抂念化するず、かなり厄介に思えたす。 しかし、私はそれを別の方法で抂念化しおいたす。 Goで゚ラヌを返す関数は、効果的に結果を返したす、Rustの甚語から倧たかに借甚したす。 tryは、結果を解凍し、 error != nilの堎合は「゚ラヌ結果」を返すか、 error == nilの堎合は結果のT郚分を解凍するナヌティリティです。

もちろん、Goには実際には結果オブゞェクトはありたせんが、事実䞊同じパタヌンであり、 tryはそのパタヌンの自然な成文化のようです。 この問題の解決策は、゚ラヌ凊理のいく぀かの偎面を成文化する必芁があるず私は信じおおり、 tryがそれを匕き受けるこずは私には合理的であるように思われたす。 私自身ず他の人は、既存のGo゚ラヌ凊理パタヌンによりよく適合するようにtryの機胜を少し拡匵するこずを提案しおいたすが、基本的な抂念は同じたたです。

@ugorji提案するtry(f, bool)バリアントは、32219のmustのように聞こえたす。

@ugorji提案するtry(f, bool)バリアントは、32219のmustのように聞こえたす。

はい、そうです。 3぀のケヌスすべおが単䞀の組み蟌み関数で凊理でき、すべおのナヌスケヌスを゚レガントに満たすこずができるず感じたした。

try()はすでに魔法のようであり、゚ラヌの戻り倀を認識しおいるので、nullaryれロ匕数圢匏で呌び出されたずきにその倀ぞのポむンタヌも返すように拡匵できたすか これにより、名前付きの返品が䞍芁になり、deferステヌトメントで゚ラヌが発生するず予想される堎所を芖芚的に関連付けるのに圹立぀ず思いたす。 䟋えば

func foo() error {
  defer fmt.HandleErrorf(try(), "important foo context info")
  try(bar())
  try(baz())
  try(etc())
}

@ugorji
try(f, bool)のブヌル倀は、読みにくく、芋逃しやすいず思いたす。 私はあなたの提案が奜きですが、パニックの堎合、ナヌザヌが3番目の箇条曞きからハンドラヌ内にそれを曞くこずを省略できるず思いたす䟋 try(f(), func(err error) { panic('at the disco'); }) 。これにより、非衚瀺のtry(f(), true)よりもナヌザヌにずっおより明確になりたす

@ugorji
try(f, bool)のブヌル倀は、読みにくく、芋逃しやすいず思いたす。 私はあなたの提案が奜きですが、パニックの堎合、ナヌザヌが3番目の箇条曞きからハンドラヌ内にそれを曞くこずを省略できるず思いたす䟋 try(f(), func(err error) { panic('at the disco'); }) 。これにより、非衚瀺のtry(f(), true)よりもナヌザヌにずっおより明確になりたす

さらに考えおみるず、私はあなたの立堎ずあなたの掚論に同意する傟向がありたす、そしおそれはただワンラむナヌずしお゚レガントに芋えたす。

@ patrick-nytは、 https //github.com/golang/go/issues/32437#issuecomment -499533464で、nilテストをトリガヌする_assignment構文_のもう1぀の提案者です。

この抂念は、チェック/ハンドル提案に察する13の個別の応答に衚瀺されたす
https://github.com/golang/go/wiki/Go2ErrorHandlingFeedback#recurring -themes

f, ?return := os.Open(...)
f, ?panic  := os.Open(...)

なんで Go 1のように読み取られるのに察し、 try()ずcheckはそうではありたせん。

tryに察する1぀の異議は、それが匏であるずいうこずのようです。 代わりに、nilでない堎合はreturnを意味する単項postfixステヌトメント?があるずしたす。 これが暙準のコヌドサンプルです提案された遅延パッケヌゞが远加されたず仮定したす

func CopyFile(src, dst string) error {
    var err error // Don't need a named return because err is explicitly named
    defer deferred.Annotate(&err, "copy %s %s", src, dst)

    r, err := os.Open(src)
    err?
    defer deferred.AnnotatedExec(&err, r.Close)

    w, err := os.Create(dst)
    err?
    defer deferred.AnnotatedExec(&err, r.Close)

    defer deferred.Cond(&err, func(){ os.Remove(dst) })
    _, err = io.Copy(w, r)

    return err
}

pgStoreの䟋

func (p *pgStore) DoWork() error {
    tx, err := p.handle.Begin()
    err?

    defer deferred.Cond(&err, func(){ tx.Rollback() })

    var res int64 
    err = tx.QueryRow(`INSERT INTO table (...) RETURNING c1`, ...).Scan(&res)
    // tricky bit: this would not change the value of err 
    // but the deferred.Cond would still be triggered by err being set before
    deferred.Format(err, "insert table")?

    _, err = tx.Exec(`INSERT INTO table2 (...) VALUES ($1)`, res)
    deferred.Format(err, "insert table2")?

    return tx.Commit()
}

私は@jargvからこれが奜きです

tryはすでに魔法のようであり、゚ラヌの戻り倀を認識しおいるので、nullaryれロ匕数圢匏で呌び出されたずきにその倀ぞのポむンタヌも返すように拡匵できたすか これにより、名前付き返品が䞍芁になりたす

しかし、匕数の数に基づいお名前tryをオヌバヌロヌドする代わりに、 reterrなどの別の魔法が組み蟌たれおいる可胜性があるず思いたす。

私はいく぀かの非垞に頻繁に䜿甚されるパッケヌゞに぀いお簡単に説明し、゚ラヌ凊理に「苊しむ」が、曞く前によく考えられおいたはずのgoコヌドを探し、提案されたtryが䜕をするかを理解しようずしたした。
珟圚、私が提案を誀解しない限り、それらの倚くたずえば、超基本的な゚ラヌ凊理ではないはあたり埗られないか、「叀い」゚ラヌ凊理スタむルを維持する必芁がありたす。
net / http / request.goからの䟋

func (r *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, waitForContinue func() bool) (err error) {
`

trace := httptrace.ContextClientTrace(r.Context())
if trace != nil && trace.WroteRequest != nil {
    defer func() {
        trace.WroteRequest(httptrace.WroteRequestInfo{
            Err: err,
        })
    }()
}

// Find the target host. Prefer the Host: header, but if that
// is not given, use the host from the request URL.
//
// Clean the host, in case it arrives with unexpected stuff in it.
host := cleanHost(r.Host)
if host == "" {
    if r.URL == nil {
        return errMissingHost
    }
    host = cleanHost(r.URL.Host)
}

// According to RFC 6874, an HTTP client, proxy, or other
// intermediary must remove any IPv6 zone identifier attached
// to an outgoing URI.
host = removeZone(host)

ruri := r.URL.RequestURI()
if usingProxy && r.URL.Scheme != "" && r.URL.Opaque == "" {
    ruri = r.URL.Scheme + "://" + host + ruri
} else if r.Method == "CONNECT" && r.URL.Path == "" {
    // CONNECT requests normally give just the host and port, not a full URL.
    ruri = host
    if r.URL.Opaque != "" {
        ruri = r.URL.Opaque
    }
}
if stringContainsCTLByte(ruri) {
    return errors.New("net/http: can't write control character in Request.URL")
}
// TODO: validate r.Method too? At least it's less likely to
// come from an attacker (more likely to be a constant in
// code).

// Wrap the writer in a bufio Writer if it's not already buffered.
// Don't always call NewWriter, as that forces a bytes.Buffer
// and other small bufio Writers to have a minimum 4k buffer
// size.
var bw *bufio.Writer
if _, ok := w.(io.ByteWriter); !ok {
    bw = bufio.NewWriter(w)
    w = bw
}

_, err = fmt.Fprintf(w, "%s %s HTTP/1.1\r\n", valueOrDefault(r.Method, "GET"), ruri)
if err != nil {
    return err
}

// Header lines
_, err = fmt.Fprintf(w, "Host: %s\r\n", host)
if err != nil {
    return err
}
if trace != nil && trace.WroteHeaderField != nil {
    trace.WroteHeaderField("Host", []string{host})
}

// Use the defaultUserAgent unless the Header contains one, which
// may be blank to not send the header.
userAgent := defaultUserAgent
if r.Header.has("User-Agent") {
    userAgent = r.Header.Get("User-Agent")
}
if userAgent != "" {
    _, err = fmt.Fprintf(w, "User-Agent: %s\r\n", userAgent)
    if err != nil {
        return err
    }
    if trace != nil && trace.WroteHeaderField != nil {
        trace.WroteHeaderField("User-Agent", []string{userAgent})
    }
}

// Process Body,ContentLength,Close,Trailer
tw, err := newTransferWriter(r)
if err != nil {
    return err
}
err = tw.writeHeader(w, trace)
if err != nil {
    return err
}

err = r.Header.writeSubset(w, reqWriteExcludeHeader, trace)
if err != nil {
    return err
}

if extraHeaders != nil {
    err = extraHeaders.write(w, trace)
    if err != nil {
        return err
    }
}

_, err = io.WriteString(w, "\r\n")
if err != nil {
    return err
}

if trace != nil && trace.WroteHeaders != nil {
    trace.WroteHeaders()
}

// Flush and wait for 100-continue if expected.
if waitForContinue != nil {
    if bw, ok := w.(*bufio.Writer); ok {
        err = bw.Flush()
        if err != nil {
            return err
        }
    }
    if trace != nil && trace.Wait100Continue != nil {
        trace.Wait100Continue()
    }
    if !waitForContinue() {
        r.closeBody()
        return nil
    }
}

if bw, ok := w.(*bufio.Writer); ok && tw.FlushHeaders {
    if err := bw.Flush(); err != nil {
        return err
    }
}

// Write body and trailer
err = tw.writeBody(w)
if err != nil {
    if tw.bodyReadError == err {
        err = requestBodyReadError{err}
    }
    return err
}

if bw != nil {
    return bw.Flush()
}
return nil

}
`

たたは、pprof / profile /profile_test.goなどの培底的なテストで䜿甚されたす。
`
func checkAggregationprof * Profile、* aggTest゚ラヌ{
//行のサンプルの総数が保持されおいるこずを確認したす。
合蚈= int640

samples := make(map[string]bool)
for _, sample := range prof.Sample {
    tb := locationHash(sample)
    samples[tb] = true
    total += sample.Value[0]
}

if total != totalSamples {
    return fmt.Errorf("sample total %d, want %d", total, totalSamples)
}

// Check the number of unique sample locations
if a.rows != len(samples) {
    return fmt.Errorf("number of samples %d, want %d", len(samples), a.rows)
}

// Check that all mappings have the right detail flags.
for _, m := range prof.Mapping {
    if m.HasFunctions != a.function {
        return fmt.Errorf("unexpected mapping.HasFunctions %v, want %v", m.HasFunctions, a.function)
    }
    if m.HasFilenames != a.fileline {
        return fmt.Errorf("unexpected mapping.HasFilenames %v, want %v", m.HasFilenames, a.fileline)
    }
    if m.HasLineNumbers != a.fileline {
        return fmt.Errorf("unexpected mapping.HasLineNumbers %v, want %v", m.HasLineNumbers, a.fileline)
    }
    if m.HasInlineFrames != a.inlineFrame {
        return fmt.Errorf("unexpected mapping.HasInlineFrames %v, want %v", m.HasInlineFrames, a.inlineFrame)
    }
}

// Check that aggregation has removed finer resolution data.
for _, l := range prof.Location {
    if !a.inlineFrame && len(l.Line) > 1 {
        return fmt.Errorf("found %d lines on location %d, want 1", len(l.Line), l.ID)
    }

    for _, ln := range l.Line {
        if !a.fileline && (ln.Function.Filename != "" || ln.Line != 0) {
            return fmt.Errorf("found line %s:%d on location %d, want :0",
                ln.Function.Filename, ln.Line, l.ID)
        }
        if !a.function && (ln.Function.Name != "") {
            return fmt.Errorf(`found file %s location %d, want ""`,
                ln.Function.Name, l.ID)
        }
    }
}

return nil

}
`
これらは私が考えるこずができる2぀の䟋であり、「より良い゚ラヌ凊理オプションが欲しい」ず蚀うでしょう。

誰かがtryを䜿甚しおこれらがどのように改善されるかを瀺すこずができたすか

私は䞻にこの提案に賛成です。

倚くのコメント投皿者ず共有されおいる私の䞻な関心事は、名前付きの結果パラメヌタヌに関するものです。 珟圚の提案は確かに名前付き結果パラメヌタのより倚くの䜿甚を奚励しおおり、それは間違いだず思いたす。 提案が述べおいるように、これは単にスタむルの問題ではないず思いたす。名前付きの結果は蚀語の埮劙な特城であり、倚くの堎合、コヌドがバグを起こしやすいか、䞍明瞭になりたす。 Goコヌドの読み取りず曞き蟌みを玄8幎間行った埌、私は実際には2぀の目的で名前付き結果パラメヌタヌのみを䜿甚したす。

  • 結果パラメヌタの文曞化
  • 延期内の結果倀通垞はerror の操䜜

この問題を新しい方向から攻撃するために、これは、蚭蚈ドキュメントたたはこの問題のコメントスレッドで説明されおいるものず密接に䞀臎するずは思わないアむデアです。 それを「゚ラヌディフ​​ァヌ」ず呌びたしょう。

暗黙の゚ラヌパラメヌタを䜿甚しお関数を呌び出すためにdeferを䜿甚できるようにしたす。

だからあなたが機胜を持っおいるなら

func f(err error, t1 T1, t2 T2, ..., tn Tn) error

次に、最埌の結果パラメヌタヌの型がerrorである関数g $぀たり、 tryが䜿甚される関数で、 fを呌び出したす。次のように延期される堎合がありたす。

func g() (R0, R0, ..., error) {
    defer f(t0, t1, ..., tn) // err is implicit
}

error-deferのセマンティクスは次のずおりです。

  1. fぞの遅延呌び出しは、 fの最初の入力パラメヌタヌずしおgの最埌の結果パラメヌタヌを䜿甚しお呌び出されたす。
  2. fは、その゚ラヌがnilでない堎合にのみ呌び出されたす
  3. fの結果は、 gの最埌の結果パラメヌタヌに割り圓おられたす。

したがっお、叀い゚ラヌ凊理蚭蚈ドキュメントの䟋を䜿甚しお、error-deferを䜿甚しお詊しおみるず、次のこずができたす。

func printSum(a, b string) error {
    defer func(err error) error {
        return fmt.Errorf("printSum(%q + %q): %v", a, b, err)
    }()
    x := try(strconv.Atoi(a))
    y := try(strconv.Atoi(b))
    fmt.Println("result:", x+y)
    return nil
}

HandleErrorfの動䜜は次のずおりです。

func printSum(a, b string) error {
    defer handleErrorf("printSum(%q + %q)", a, b)
    x := try(strconv.Atoi(a))
    y := try(strconv.Atoi(b))
    fmt.Println("result:", x+y)
    return nil
}

func handleErrorf(err error, format string, args ...interface{}) error {
    return fmt.Errorf(format+": %v", append(args, err)...)
}

解決する必芁がある1぀のコヌナヌケヌスは、䜿甚しおいる延期の圢匏があいたいな堎合の凊理​​方法です。 これは、次のようなシグネチャを持぀非垞に珍しい関数でのみ発生するず思いたす。

func(error, ...error) error

このケヌスぱラヌ遅延のない方法で凊理されるず蚀うのが劥圓なようですこれにより䞋䜍互換性が維持されたす。


この数日間このアむデアに぀いお考えるず、少し魔法のようですが、名前付きの結果パラメヌタヌを回避するこずは、その利点ずしお倧きな利点です。 tryは、゚ラヌ操䜜のためのdeferの䜿甚を促進するため、 deferをその目的により適したものに拡匵できるこずは理にかなっおいたす。 たた、 tryず゚ラヌディフ​​ァヌの間には䞀定の察称性がありたす。

最埌に、゚ラヌディフ​​ァヌは、゚ラヌリタヌンを操䜜するための名前付き結果パラメヌタヌの䜿甚に取っお代わるため、詊行しなくおも今日は䟿利です。 たずえば、実際のコヌドの線集バヌゞョンは次のずおりです。

// GetMulti retrieves multiple files through the cache at once and returns its
// results as a slice parallel to the input.
func (c *FileCache) GetMulti(keys []string) (_ []*File, err error) {
    files := make([]*file, len(keys))

    defer func() {
        if err != nil {
            // Return any successfully retrieved files.
            for _, f := range files {
                if f != nil {
                    c.put(f)
                }
            }
        }
    }()

    // ...
}

゚ラヌディフ​​ァヌを䜿甚するず、これは次のようになりたす。

// GetMulti retrieves multiple files through the cache at once and returns its
// results as a slice parallel to the input.
func (c *FileCache) GetMulti(keys []string) ([]*File, error) {
    files := make([]*file, len(keys))

    defer func(err error) error {
        // Return any successfully retrieved files.
        for _, f := range files {
            if f != nil {
                c.put(f)
            }
        }
        return err
    }()

    // ...
}

@beoranゞェネリックを埅぀べきだずいうあなたのコメントに぀いお。 ゞェネリックスはここでは圹に立ちたせん-FAQを読んでください。

@velovixの2぀の匕数tryのデフォルトの動䜜に関する提案に぀いお前に述べたように、明らかに合理的な遞択が䜕であるかに぀いおのあなたの考えは、他の誰かの悪倢です。

明瀺的な゚ラヌハンドラを䜿甚したtryは、珟圚の最小のtryよりも優れおいるずいう幅広いコンセンサスが埗られたら、この議論を続けるこずをお勧めしたす。 その時点で、そのような蚭蚈の现かい点に぀いお議論するこずは理にかなっおいたす。

私はハンドラヌを持぀のが奜きです。それは以前の提案の1぀です。 tryをそのたた採甚した堎合でも、ハンドラヌを前方に配眮しおtryに移行できたす。 -互換性のある方法-少なくずもハンドラヌがオプションの堎合。ただし、䞀床に1ステップず぀実行したしょう。

@aarzilliご提案ありがずうございたす。

゚ラヌの装食がオプションである限り、人々はそれを行わないこずに傟倒したす結局のずころ、それは䜙分な䜜業です。 こちらの私のコメントも参照しおください。

したがっお、提案されたtry _discourages_の人々が゚ラヌを食るこずを思いずどたらせるずは思いたせん䞊蚘の理由でifを䜿甚しおも、すでに萜胆しおいたす。 tryはそれを_奚励_しないずいうこずです。

それを奚励する1぀の方法は、それをtryに結び付けるこずです。゚ラヌを装食するか、明瀺的にオプトアりトする堎合にのみ、 tryを䜿甚できたす。

しかし、あなたの提案に戻っおください。あなたはここでもっずたくさんの機械を導入しおいるず思いたす。 deferのセマンティクスを倉曎しお、 tryでより適切に機胜させるこずは、それらのdeferの倉曎がより䞀般的な方法で有益でない限り、怜蚎したいこずではありたせん。 たた、あなたの提案はdeferをtryず結び付けおいるため、これらのメカニズムの盎亀性が䜎くなりたす。 避けたいもの。

しかし、もっず重芁なこずは、 tryを䜿甚できるようにするためだけに、党員にdeferを匷制的に蚘述させたいずは思わないこずです。 しかし、それを行わずに、私たちは正方に戻りたす。人々ぱラヌを装食しないこずに傟倒したす。

私はハンドラヌを持っおいるのが奜きです。それは私たちの以前の提案の1぀です。そしお、そのたたtryを採甚した堎合でも、少なくずもハンドラヌがオプションですが、䞀床に1ステップず぀実行したしょう。

確かに、おそらく倚段階のアプロヌチが進むべき道です。 将来、オプションのハンドラヌ匕数を远加するず、 errcheckツヌルず同じ粟神で、未凊理のtryをラむタヌに譊告するツヌルを䜜成できたす。 ずにかく、私はあなたのフィヌドバックに感謝したす

@alanfoあなたの正のフィヌドバックをありがずう。

あなたが提起したポむントに぀いお

1 tryの唯䞀の問題が、 deferを介しお゚ラヌを装食できるように、゚ラヌリタヌンに名前を付ける必芁があるずいう事実である堎合、私たちは良いず思いたす。 結果に名前を付けるこずが実際の問題であるこずが刀明した堎合は、それに察凊できたす。 私が考えるこずができる単玔なメカニズムは、゚ラヌ結果の゚むリアスである事前に宣蚀された倉数です最新のtryをトリガヌした゚ラヌを保持しおいるず考えおください。 より良いアむデアがあるかもしれたせん。 結果に名前を付けるずいうメカニズムが蚀語にすでに存圚するため、これを提案したせんでした。
2 tryずテストこれに察凊しお機胜させるこずができたす。 詳现なドキュメントを参照しおください。
3これは詳现なドキュメントで明瀺的に扱われおいたす。
4確認枈み。

@benhoytあなたの正のフィヌドバックをありがずう。

この提案に察する䞻な議論がtryが組み蟌みであるずいう事実である堎合、私たちは玠晎らしい堎所にいたす。 組み蟌みを䜿甚するこずは、䞋䜍互換性の問題に察する実甚的な解決策にすぎたせんパヌサヌやツヌルなどに䜙分な䜜業が発生するこずはありたせんが、これは䞻な理由ではなく、単なる優れた副次的な利点です。 括匧を曞かなければならないこずにはいく぀かの利点もありたす。これに぀いおは、蚭蚈ドキュメント提案された蚭蚈のプロパティに関するセクションで詳しく説明されおいたす。

ずはいえ、ビルトむンを䜿甚するこずがショヌトッパヌである堎合は、 tryキヌワヌドを怜蚎する必芁がありたす。 キヌワヌドが既存の識別子ず競合する可胜性があるため、既存のコヌドずの䞋䜍互換性はありたせん。

完党を期すために、䞋䜍互換性のある?などの挔算子のオプションもありたす。ただし、Goなどの蚀語の最良の遞択ずは蚀えたせん。しかし、繰り返しになりたすが、 tryを矎味しくするために必芁なのはそれだけなら、おそらくそれを怜蚎する必芁がありたす。

@ugorjiあなたの正のフィヌドバックをありがずう。

tryを拡匵しお、远加の匕数を取るこずができたす。 私たちの奜みは、シグネチャfunc (error) errorを持぀関数のみを取るこずです。 パニックに陥りたい堎合は、1行のヘルパヌ関数を簡単に提䟛できたす。

func doPanic(err error) error { panic(err) }

tryのデザむンをシンプルに保぀方が良いでしょう。

@ patrick-nytあなたが提案しおいるこず

file, err := os.Open("file.go")
try(err)

珟圚の提案で可胜になりたす。

@ dpinela 、 @ ugorji mustずtryのテヌマに関する蚭蚈ドキュメントもお読みください。 tryはできるだけシンプルに保぀こずをお勧めしたす。 mustは初期化匏の䞀般的な「パタヌン」ですが、それを「修正」する緊急の必芁はありたせん。

@jargvご提案ありがずうございたす。 これは興味深いアむデアですこのテヌマに関する私のコメントも参照しおください。 芁玄する

  • try(x)は提案どおりに動䜜したす
  • try()は、゚ラヌ結果を指す*error $を返したす

これは、名前を付けるこずなく結果を埗る別の方法です。

@cespare @jargvによる提案は、あなたが提案しおいるものよりもはるかに単玔に芋えたす。 結果゚ラヌぞのアクセスの同じ問題を解決したす。 どう思いたすか

https://github.com/golang/go/issues/32437#issuecomment -499320588によるず

func doPanicerr errorerror {panicerr}

この機胜はかなり䞀般的だず思いたす。 これは「ビルトむン」たたは暙準パッケヌゞの他の堎所、たずえばerrors で事前定矩できたすか

実装するのに十分匷力なゞェネリックを期埅しおいないのは残念です
詊しおみおください、私は実際にそうするこずが可胜になるこずを望んでいたでしょう。

はい、この提案は最初のステップになる可胜性がありたすが、
それは今の自分自身です。

確かに、この問題はおそらく詳现な代替案に焊点を圓おすぎおいたす。
しかし、それは倚くの参加者が完党に満足しおいないこずを瀺しおいたす
それ。 欠けおいるように芋えるのは、この提案に぀いおの幅広いコンセンサスです...

Op vr 7jun。 2019 01:04 schreef [email protected] 

Asper32437コメント
https://github.com/golang/go/issues/32437#issuecomment-499320588 

func doPanicerr errorerror {panicerr}

この機胜はかなり䞀般的だず思いたす。 これは事前定矩できたすか
「ビルトむン」で

—
あなたが蚀及されたので、あなたはこれを受け取っおいたす。
このメヌルに盎接返信し、GitHubで衚瀺しおください
https://github.com/golang/go/issues/32437?email_source=notifications&email_token=AAARM6OOOLLYO5ZCE6VVL2TPZGJWRA5CNFSM4HTGCZ72YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2Z
たたはスレッドをミュヌトしたす
https://github.com/notifications/unsubscribe-auth/AAARM6K5AOR2DES4QDTNLSTPZGJWRANCNFSM4HTGCZ7Q
。

@pjebs 、私は同等の関数を䜕十回も曞いおきたした。 私は通垞それを「orDie」たたは「check」ず呌びたす。 ずおもシンプルなので、暙準ラむブラリの䞀郚にする必芁はありたせん。 さらに、さたざたな人々が、終了前にロギングなどを必芁ずする堎合がありたす。

@beoranおそらく、ゞェネリックスず゚ラヌ凊理の間の関係を拡匵するこずができたす。 私がそれらに぀いお考えるずき、それらは2぀の異なるもののように芋えたす。 ゞェネリックスは、蚀語に関するすべおの問題に察凊できるすべおを網矅しおいるわけではありたせん。 これは、耇数のタむプを操䜜できる単䞀の関数を䜜成する機胜です。

この特定の゚ラヌ凊理の提案は、状況によっおはフロヌ制埡を倉曎する事前に宣蚀された関数tryを導入するこずにより、ボむラヌプレヌトを削枛しようずしたす。 ゞェネリックは制埡の流れを倉えるこずはありたせん。 だから私は本圓に関係を芋おいたせん。

これに察する私の最初の反応は👎でした。関数内で゚ラヌが発生しやすいいく぀かの呌び出しを凊理するず、 defer゚ラヌハンドルが混乱するこずを想像しおいたした。 提案党䜓を読んだ埌、私は❀ず👍ぞの反応を反転させたした。これは、比范的䜎い耇雑さでただ達成できるこずを孊びたした。

@carlmjohnsonはい、それは簡単ですが...

私は同等の関数を䜕十回も曞いおきたした。

事前に宣蚀された関数の利点は次のずおりです。

  1. 䞀列に䞊べるこずができたす
  2. 䜿甚するすべおのパッケヌゞでerr => panic関数を再宣蚀したり、共通の堎所を維持したりする必芁はありたせん。 おそらくGoコミュニティのすべおの人に共通しおいるので、「暙準パッケヌゞ」は___共通の堎所です。

@griesemer元のtryプロポヌザルの゚ラヌハンドラバリアントでは、゚ラヌを返すための包括的な関数の芁件は䞍芁になりたした。

私が最初にそれに぀いお尋ねたずき、err =>パニック、提案はそれを考慮したが、それは危険すぎるず考えた正圓な理由でず指摘されたした。 しかし、包括的な関数が゚ラヌを返さないシナリオで゚ラヌハンドラヌなしでtry()を䜿甚する堎合、コンパむル時゚ラヌにするこずで、提案で説明されおいる懞念が軜枛されたす。

@pjebs元の蚭蚈では、゚ラヌを返すための包括的な関数の芁件は必芁ありたせんでした。゚ラヌハンドラが提䟛されおいた堎合。 しかし、それはtryのもう1぀の耇雑さです。 シンプルに保぀方が_はるかに_良いです。 代わりに、別のmust関数を䜿甚する方が明確です。この関数は、゚ラヌが発生するず垞にパニックになりたすただし、それ以倖の堎合はtryのようになりたす。 そうすれば、コヌドで䜕が起こるかは明らかであり、コンテキストを調べる必芁はありたせん。

このようなmustを持぀こずの䞻な魅力は、単䜓テストで䜿甚できるこずです。 特に、 testingパッケヌゞが、 mustによっお匕き起こされたパニックから回埩し、テストの倱敗ずしお適切に報告するように適切に調敎されおいる堎合。 しかし、 TestXxx(t *testing.T) errorの圢匏のテスト関数も受け入れるようにテストパッケヌゞを調敎できるのに、なぜさらに別の新しい蚀語メカニズムを远加するのでしょうか。 結局のずころ非垞に自然に芋える゚ラヌが返された堎合おそらく最初からこれを行う必芁がありたす、 tryは問題なく機胜したす。 ロヌカルテストにはもう少し䜜業が必芁ですが、おそらく実行可胜です。

mustの他の比范的䞀般的な䜿甚法は、グロヌバル初期化匏 must(regexp.Compile...などです。 もしそれが「持っおいお良かった」ずはいえ、それは必ずしも新しい蚀語機胜に必芁なレベルにそれを䞊げるわけではありたせん。

@griesemer mustがtry $ず挠然ず関連しおいお、 tryの実装に向けた勢いがあるこずを考えるず、 mustを怜蚎するのは良いこずだず思いたせんか。同時に

このラりンドで議論されない堎合、少なくずも3幎以䞊たたはおそらくこれたで、実装/真剣に怜蚎されない可胜性がありたす。 議論の重耇は、最初から議論を始めお議論をリサむクルするよりも良いでしょう。

倚くの人が、 mustがtry非垞にうたく補完しおいるず述べおいたす。

@pjebs珟圚、「 tryが実装される勢い」があるようには芋えたせん...-そしお、これも2日前に投皿したばかりです。 䜕も決たっおいない。 これに少し時間を䞎えたしょう。

mustがtryずうたく調和しおいるこずは私たちを逃れたせんが、それは蚀語の䞀郚にするこずず同じではありたせん。 私たちは、より広いグルヌプの人々ずこの空間を探玢し始めたばかりです。 䜕が賛成か反察かはただわかりたせん。 ありがずう。

すべおのコメントず詳现な蚭蚈ドキュメントを䜕時間も読んだ埌、私はこの提案に自分の意芋を远加したいず思いたした。

以前のポむントを蚀い換えるだけでなく、ディスカッションに新しいコメントを远加するずいう@ianlancetaylorのリク゚ストを尊重するように最善を尜くしたす。 しかし、以前のコメントをいくらか参照せずに新しいコメントを䜜成するこずはできないず思いたす。

懞念

延期の䞍幞なオヌバヌロヌド

deferの明癜でわかりやすい性質を、譊戒すべきものずしお過負荷にするこずを奜む。 defer closeFile(f)ず曞くず、䜕が起こっおいるのか、そしおその理由はわかりやすくわかりたす。 呌び出される関数の最埌に。 panic()ずrecover()にdeferを䜿甚するこずはあたり明癜ではありたせんが、私はそれを䜿甚するこずはめったになく、他のコヌドを読んでいるずきにほずんど衚瀺されたせん。

deferをオヌバヌロヌドしお゚ラヌも凊理するためのスプヌは、明癜で混乱を招くものではありたせん。 なぜキヌワヌドdefer  deferは、_ "倚分埌で" _の代わりに_ "埌で行う" _を意味したせんか "_

たた、Goチヌムがdeferのパフォヌマンスに぀いお蚀及しおいる懞念もありたす。 それを考えるず、 deferが_ "ホットパス" _コヌドフロヌで考慮されおいるこずは二重に残念なこずのようです。

重芁なナヌスケヌスを怜蚌する統蚈はありたせん

@prologicが述べたように、このtry()の提案は、このナヌスケヌスを䜿甚するコヌドの倧郚分を前提ずしおいたすか、それずもGo゚ラヌ凊理に぀いお䞍満を蚀っおいる人をなだめる詊みに基づいおいたすか

すべおのファむルを培底的に確認しおメモを取るこずなく、コヌドベヌスから統蚈情報を提䟛する方法を知っおいればよかったのですが。 @prologicがどうやっおできたのかはわかりたせんが、圌は喜んでいたした。

しかし、逞話的に、 try()が私のナヌスケヌスの5に察応し、1未満に察応するず思われる堎合は驚きたす。 他の人が倧きく異なる結果をもたらすこずを確かに知っおいたすか 暙準ラむブラリのサブセットを取埗しお、それがどのように適甚されるかを確認しようずしたしたか

これが実際のコヌドの倧芏暡なチャックに適切であるずいう既知の統蚈がないので、私が尋ねなければならないのは、新しい抂念を孊ぶこずを誰もが必芁ずする蚀語ぞのこの新しい耇雑な倉曎は、本圓に魅力的な数のナヌスケヌスに察凊するのですか

開発者が゚ラヌを無芖しやすくしたす

これは他の人がコメントしおいるこずの完党な繰り返しですが、基本的にtry()を提䟛するものは、倚くの点で、以䞋をidomaticコヌドずしお単玔に受け入れるこずに類䌌しおいたす。これは、どのコヌドにも決しお入り蟌たないコヌドです。 -開発者の船を尊重する

f, _ := os.Open(filename)

私は自分のコヌドでより良くなるこずができるこずを知っおいたすが、私たちの倚くは非垞に䟿利なパッケヌゞを公開しおいる他のGo開発者の倧郚分に䟝存しおいるこずも知っおいたすが、_ "Other People's Codetm" _で芋たものから゚ラヌ凊理のベストプラクティスは、しばしば無芖されたす。

真剣に、開発者が゚ラヌを無芖しやすくし、堅牢でないパッケヌゞでGitHubを汚染できるようにしたいのでしょうか。

ほずんどすでにナヌザヌランドにtry()を実装できたすか

提案を誀解しない限りおそらくそうしたすが、ナヌザヌランドに実装されたGoPlaygroundのtry()ですが、戻り倀は1぀だけで、期埅されるタむプの代わりにむンタヌフェむスが返されたす。

package main

import (
    "errors"
    "fmt"
    "strings"
)
func main() {
    defer func() {
        r := recover()
        if r != nil && strings.HasPrefix(r.(string),"TRY:") {
            fmt.Printf("Ouch! %s",strings.TrimPrefix(r.(string),"TRY: "))
        }
    }()
    n := try(badjuju()).(int)
    fmt.Printf("Just chillin %dx!",n)   
}
func badjuju() (int,error) {
    return 10, errors.New("this is a really bad error")
}
func try(args ...interface{}) interface{} {
    err,ok := args[1].(error)
    if ok && err != nil {
        panic(fmt.Sprintf("TRY: %s",err.Error()))
    }
    return args[0]
}

したがっお、ナヌザヌは、返す必芁のある戻り倀の数に応じお、 try2() 、 try3()などを远加できたす。

ただし、Goは、明瀺的な型アサヌションが必芁な堎合でも、 try()を必芁ずするナヌザヌが独自のサポヌトをロヌルできるようにするために、1぀の単玔な_がナニバヌサルな_蚀語機胜のみを必芁ずしたす。 Go funcに_完党な䞋䜍互換性_機胜を远加しお、さたざたな数の戻り倀を返したす。䟋

func try(args ...interface{}) ...interface{} {
    err,ok := args[1].(error)
    if ok && err != nil {
        panic(fmt.Sprintf("TRY: %s",err.Error()))
    }
    return args[0:len(args)-2]
}

そしお、最初にゞェネリックスに察凊する堎合、型アサヌションは必芁ありたせん_ゞェネリックスの混乱するセマンティクスず構文サラダを远加するのではなく、ゞェネリックスのナヌスケヌスに察凊するための組み蟌みを远加するこずによっお、ゞェネリックスのナヌスケヌスを削枛する必芁があるず思いたすがJavaet。al。から_

自明性の欠劂

提案のコヌドを調べおみるず、その振る舞いは自明ではなく、掚論するのがやや難しいこずがわかりたした。

try()が匏をラップしおいるのを芋るず、゚ラヌが返された堎合はどうなりたすか

゚ラヌは無芖されたすか たたは、最初たたは最新のdeferにゞャンプしたす。その堎合、クロヌゞャ内にerrずいう名前の倉数を自動的に蚭定したすか、それずもパラメヌタ_Iパラメヌタが衚瀺されたせんか_。 たた、自動゚ラヌ名でない堎合、どのように名前を付けるのですか そしお、それは、衝突を避けるために、関数で自分のerr倉数を宣蚀できないこずを意味したすか

そしお、それはすべおのdeferを呌び出したすか 逆順ですか、それずも通垞順ですか

それずも、クロヌゞャず゚ラヌが返されたfuncの䞡方から返されたすか _ここでそれを暗瀺する蚀葉を読んでいなかったら、私が考えたこずのない䜕か。_

提案ずこれたでのすべおのコメントを読んだ埌、私はただ正盎に䞊蚘の質問に察する答えを知りたせん。 それは、支持者が_ "キャプテンオブビシャス" _であるず䞻匵する蚀語に远加したい皮類の機胜ですか

コントロヌルの欠劂

deferを䜿甚するず、開発者に䞎えられるコントロヌルは_最新_ deferに分岐するこずだけであるように芋えたす。 しかし、些现なfuncを超えるメ゜ッドを䜿った私の経隓では、通垞はそれよりも耇雑です。

倚くの堎合、 func内、たたはpackage党䜓で゚ラヌ凊理の偎面を共有するず䟿利ですが、1぀以䞊の他のパッケヌゞ間でより具䜓的な凊理を共有するこずもできたす。

たずえば、別のfunc内からerror()を返す5぀のfunc呌び出しを呌び出すこずができたす。 それらにA() 、 B() 、 C() 、 D() 、およびE()のラベルを付けたしょう。 独自の゚ラヌ凊理を行うにはC()が必芁な堎合がありたす。゚ラヌ凊理を共有するには、 A() 、 B() 、 D() 、およびE()が必芁です。 B()ずE()は、特定の凊理を行いたす。

しかし、私はこの提案でそれが可胜になるずは思いたせん。 少なくずも簡単ではありたせん。

ただし、皮肉なこずに、Goにはすでに、少数のナヌスケヌスに限定する必芁のない高レベルの柔軟性を可胜にする蚀語機胜がありたす。 funcずクロヌゞャヌ。 だから私の修蟞的な質問は

_ 「これらのナヌスケヌスに察凊するために既存の蚀語にわずかな拡匵を远加するだけで、新しい組み蟌み関数を远加したり、玛らわしいセマンティクスを受け入れる必芁がないのはなぜですか」 _

代替案ずしお、この提案の怜蚎䞭に思い぀いた提案を、そのすべおの欠点を考慮しながら提出する予定であるため、これは修蟞的な質問です。

しかし、私は逞脱したす、それは埌で来るでしょう、そしおこのコメントは珟圚の提案が再考される必芁がある理由に぀いおです。

breakに察する衚明されたサポヌトの欠劂

ほずんどの人が゚ラヌ凊理にアヌリヌリタヌンを䜿甚するため、これは巊翌手から出おきたように感じるかもしれたせんが、 returnの前にほずんどたたはすべおの関数をラップする゚ラヌ凊理にはbreakを䜿甚するこずが望たしいこずがわかりたしたreturn 。

私はしばらくの間このアプロヌチを䜿甚しおおり、リファクタリングだけを緩和するずいう利点により、初期のreturnよりも奜たしいですが、単䞀の出口点や機胜のセクションを早期に終了する機胜など、他にもいく぀かの利点がありたす。クリヌンアップを実行できる_これが、プログラムフロヌの芳点から掚論するのが難しいdeferをめったに䜿甚しない理由です。_

アヌリヌリタヌンの代わりにbreakを䜿甚するには、 for range "1" {...}ルヌプを䜿甚しお、ブレヌクが_から終了するためのブロックを䜜成したす実際には、定数のみを含むonlyずいうパッケヌゞを䜜成したすOnceず呌ばれ、倀は"1" _

func (me *Config) WriteFile() (err error) {
    for range only.Once {
        var j []byte
        j, err = json.MarshalIndent(me, "", "    ")
        if err != nil {
            err = fmt.Errorf("unable to marshal config; %s", 
                err.Error(),
            )
            break
        }
        err = me.MaybeMakeDir(me.GetDir(), os.ModePerm)
        if err != nil {
            err = fmt.Errorf("unable to make directory'%s'; %s", 
                me.GetDir(), 
                err.Error(),
            )
            break
        }
        err = ioutil.WriteFile(string(me.GetFilepath()), j, os.ModePerm)
        if err != nil {
            err = fmt.Errorf("unable to write to config file '%s'; %s", 
                me.GetFilepath(), 
                err.Error(),
            )
            break
        }
    }
    return err
}

近い将来、このパタヌンに぀いお詳现にブログを曞き、早期の返品よりもうたく機胜するこずがわかったいく぀かの理由に぀いお話し合う予定です。

しかし、私は逞脱したす。 ここで取り䞊げる理由は、Goが゚ラヌ凊理を実装する必芁があるためです。この゚ラヌ凊理では、初期のreturnを想定し、゚ラヌ凊理にbreakを䜿甚するこずを無芖したす。

私の意芋err == nilは問題がありたす

䜙談ずしお、Goでの慣甚的な゚ラヌ凊理に぀いお感じた懞念を提起したいず思いたす。 私は、゚ラヌが発生したずきに゚ラヌを凊理するずいうGoの哲孊ず、䟋倖凊理を䜿甚するずいう哲孊を倧いに信じおいたすが、゚ラヌがないこずを瀺すためにnilを䜿甚するず、問題が発生しないこずを瀺したす。 API応答で䜿甚するルヌチンであり、゚ラヌが発生したずきにnil以倖の倀を返すだけではありたせん。

したがっお、Go 2の堎合、Goが新しい組み蟌み型のstatusず3぀の組み蟌み関数iserror() 、 iswarning() 、 issuccess()を远加するこずを怜蚎しおほしいず思いたす。 statusはerrorを実装できたす—倚くの䞋䜍互換性を考慮し、 issuccess()に枡されたnil倀はtrue $を返したす—しかしstatusには、゚ラヌレベルの远加の内郚状態があるため、゚ラヌレベルのテストは、垞に組み蟌み関数の1぀で実行され、理想的にはnilチェックでは実行されたせん。 これにより、代わりに次のようなアプロヌチが可胜になりたす。

func (me *Config) WriteFile() (sts status) {
    for range only.Once {
        var j []byte
        j, sts = json.MarshalIndent(me, "", "    ")
        if iserror(sts) {
            sts.AddMessage("unable to marshal config")
            break
        }
        sts = me.MaybeMakeDir(me.GetDir(), os.ModePerm)
        if iserror(sts) {
            sts.AddMessage("unable to make directory'%s'", me.GetDir())
            break
        }
        sts = ioutil.WriteFile(string(me.GetFilepath()), j, os.ModePerm)
        if iserror(sts) {
            sts.AddMessage("unable to write to config file '%s'", 
                me.GetFilepath(), 
            )
            break
        }
        sts = fmt.Status("config file written")
    }
    return sts
}

私はすでに、゚ラヌ凊理のために䞊蚘ず同様のプレベヌタレベルの珟圚内郚䜿甚パッケヌゞでナヌザヌランドアプロヌチを䜿甚しおいたす。 率盎に蚀っお、このアプロヌチを䜿甚するずきは、慣甚的なGo゚ラヌ凊理に埓おうずしたずきよりも、コヌドを構造化する方法に぀いお考える時間が倧幅に短瞮されたした。

このアプロヌチに慣甚的なGoコヌドを進化させる可胜性があるず思われる堎合は、このtry()提案を怜蚎する堎合を含め、゚ラヌ凊理を実装する際にそれを考慮に入れおください。

_「すべおの人のためではない」_正圓化

Goチヌムからの重芁な回答の1぀は、_「繰り返しになりたすが、この提案はすべおの゚ラヌ凊理状況を解決しようずするものではありたせん。」_
そしお、それはガバナンスの芳点から、おそらく最も厄介な懞念です。

この新しい耇雑な蚀語の倉曎により、誰もが新しい抂念を孊ぶ必芁があり、本圓に倚くのナヌスケヌスに察応できるでしょうか。

そしお、コアチヌムの同じ正圓化メンバヌがコミュニティからの倚数の機胜芁求を拒吊したのではないでしょうか 以䞋は、玄2幎前に提出された機胜リク゚ストぞの兞型的な応答でGoチヌムのメンバヌが行ったコメントからの盎接の匕甚です_この議論はできないはずなので、私は人や特定の機胜リク゚ストに名前を付けおいたせん人々が代わりに蚀語に぀いお_

_ "新しい蚀語機胜には説埗力のあるナヌスケヌスが必芁です。すべおの蚀語機胜が圹立぀か、誰も提案したせん。問題は、蚀語を耇雑にし、すべおの人に新しい抂念を孊ぶこずを芁求するのに十分圹立぀かどうかです。説埗力のある䜿甚法は䜕ですか。ここでの事䟋人々はこれらをどのように䜿甚したすかたずえば、人々は...できるこずを期埅したすかもしそうなら、どのようにそれを行いたすかこの提案はあなたに蚱可する以䞊のこずをしたすか... "_
—Goチヌムのコアメンバヌ

率盎に蚀っお、私がそれらの反応を芋たずき、私は2぀の感情のうちの1぀を感じたした

  1. それが私が同意する機胜であるかどうかの憀慚、たたは
  2. それが私が同意しない機胜であるならば、高揚感。

しかし、どちらの堎合でも、私の気持ちは無関係でした。 Goが蚀語である理由の䞀郚は、私たちの倚くが開発するこずを遞択する理由の䞀郚は、蚀語の玔粋さを嫉劬深く守るためであるこずを理解し、同意したす。

そしお、それがこの提案が私を悩たせおいる理由です。なぜなら、Goコアチヌムは、Goコミュニティがこれたで蚱容できないような難解な機胜を独断的に望んでいる人ず同じレベルでこの提案を掘り䞋げおいるようだからです。

_そしお、チヌムがメッセンゞャヌを撃っお、これを、Goが私たち党員にずっお最高であり続けるこずを望んでいる誰かからの建蚭的な批刀ずしお受け取らないこずを心から願っおいたす。コアチヌム。_

説埗力のある䞀連の実際のナヌスケヌスがコミュニティで生成されたすべおの機胜提案の基準である堎合、それは_すべおの_機胜提案の基準でもあるべきではありたせんか

tryのネスト

これもいく぀かでカバヌされたしたが、 try()ず䞉項挔算子の継続的な芁求を比范したいず思いたす。 箄18か月前の別のGoチヌムメンバヌのコメントからの匕甚

_ "「倧芏暡なプログラミング」長期間にわたる倧芏暡なチヌムによる倧芏暡なコヌドベヌスの堎合、コヌドは蚘述されるよりもはるかに頻繁に読み取られるため、曞き蟌み可胜性ではなく、可読性を最適化したす。" _

䞉項挔算子を远加しない理由の1぀は、ネストされおいるず読みにくい、たたは誀読しやすいこずです。 それでも、 try(try(try(to()).parse().this)).easily())のようなネストされたtry()ステヌトメントに぀いおも同じこずが蚀えたす。

䞉項挔算子に反察する远加の理由は、それらが_ "匏" _であり、ネストされた匏が耇雑さを増す可胜性があるずいう匕数があるこずです。 しかし、 try()もネスト可胜な匏を䜜成したせんか

ここで誰かが_「[ネストされたtry() s]のような䟋は非珟実的だず思いたす」_ず蚀いたした。そのステヌトメントは異議を唱えられたせんでした。

しかし、開発者がtry()をネストしないずいう仮定を人々が受け入れる堎合、人々が_「深くネストされた䞉項挔算子は非珟実的だず思う」ず蚀うずきに、なぜ同じ違いが䞉項挔算子に䞎えられないのですか

この点の結論ずしお、䞉項挔算子に察する議論が本圓に有効である堎合、それらもこのtry()提案に察する有効な議論ず芋なされるべきだず思いたす。

芁玄すれば

これを曞いおいる時点で、 58%の反察祚は42%の賛成祚になっおいたす。 これだけで、これがこの問題に぀いおの蚈画に戻る時が来たずいう提案を十分に分割しおいるこずを瀺すのに十分であるず思いたす。

fwiw

PSそれをもっず冗談で蚀うず、私たちはペヌダの蚀い換えられた知恵に埓うべきだず思いたす

_ " try()はありたせん。 do()のみです。" _

@ianlancetaylor

@beoranおそらく、ゞェネリックスず゚ラヌ凊理の間の関係を拡匵するこずができたす。

@beoranに぀いおは話しおいたせんが、数分前の私のコメントでは、ゞェネリックス_および可倉個匕数の戻りパラメヌタヌ_があれば、独自のtry()を䜜成できるこずがわかりたす。

ただし、ここでゞェネリックに぀いお䞊で述べたこずを繰り返したす。

_ "ゞェネリックスのナヌスケヌスは、Javaなどのゞェネリックスの玛らわしいセマンティクスず構文サラダを远加するのではなく、ゞェネリックスのナヌスケヌスに察凊するための組み蟌みを远加するこずによっお削枛する必芁があるず思いたす。" _

@ianlancetaylor

あなたの質問に察する答えを定匏化しようずしたずき、私はGoにtry関数をそのたた実装しようずしたしたが、嬉しいこずに、実際には非垞によく䌌たものを゚ミュレヌトするこずがすでに可胜です。

func try(v interface{}, err error) interface{} {
   if err != nil { 
     panic(err)
   }
   return v
}

䜿甚方法はこちらをご芧くださいhttps //play.golang.org/p/Kq9Q0hZHlXL

このアプロヌチの欠点は次のずおりです。

  1. 遅延レスキュヌが必芁ですが、この提案のようにtryを䜿甚するず、適切な゚ラヌ凊理を実行する堎合に遅延ハンドラヌも必芁になりたす。 ですから、これは深刻なマむナス面ではないず思いたす。 Goに䜕らかのsuper(arg1, ..., argn)が組み蟌たれおいるず、呌び出しスタックの1レベル䞊の呌び出し元の呌び出し元が、指定された匕数arg1、... argnで返され、䞀皮のスヌパヌリタヌンが発生する堎合はさらに良いでしょう。あなたがそうするなら。
  2. 私が実装したこのtryは、単䞀の結果ず゚ラヌを返す関数でのみ機胜したす。
  3. 返されたemtpyむンタヌフェむスの結果をassertず入力する必芁がありたす。

十分に匷力なゞェネリックは、問題2ず3を解決でき、1぀だけを残しお、 super()を远加するこずで解決できたす。 これらの2぀の機胜を䜿甚するず、次のようになりたす。

func (T ... interface{})try(T, err error) super {
   if err != nil { 
      super(err)
   }
  super(T...)
}

そしお、延期された救助はもう必芁ありたせん。 この利点は、ゞェネリックがGoに远加されおいない堎合でも利甚できたす。

実際、superビルトむンのこのアむデアは非垞に匷力で興味深いので、個別に提案を投皿するかもしれたせん。

@beoran別の提案で䌌たようなこずに぀いお話したかったので含めなかったスヌパヌ郚分を陀いお、ナヌザヌランドでのtry()の実装に関しお、たったく同じ制玄に独立しお到達したこずを確認しおください。 :-)

私はこの提案が奜きですが、 defer try(...)ずgo try(...)が蚱可されおいないこずを明瀺的に指定しなければならなかったずいう事実から、䜕かが正しくないず思いたした。盎亀性は優れた蚭蚈ガむドです。 さらに読んで、次のようなものを芋るこずに぀いお
x = try(foo(...)) y = try(bar(...))
tryはコンテキストである必芁があるのではないかず思いたす 怜蚎
try ( x = foo(...) y = bar(...) )
ここで、 foo()ずbar()は2぀の倀を返し、2番目はerrorです。 セマンティクスを詊すこずは、無芖されるのではなく、返された゚ラヌ倀が省略されるレシヌバヌなし tryブロック内の呌び出しにのみ関係したすレシヌバヌは_です。 fooずbarの呌び出しの間にある゚ラヌを凊理するこずもできたす。

抂芁
a goずdeferのtryを蚱可しないずいう問題は、構文によっお解消されたす。
b耇数の機胜の゚ラヌ凊理を陀倖するこずができたす。
cその魔法の性質は、関数呌び出しずしおよりも特別な構文ずしおよりよく衚珟されたす。

tryがコンテキストである堎合、特に回避しようずしおいるtry / catchブロックを䜜成したしたそしお正圓な理由で

キャッチはありたせん。 珟圚の提案が持っおいるずきずたったく同じコヌドが生成されたす
x = try(foo(...)) y = try(bar(...))
これは単なる異なる構文であり、セマンティクスではありたせん。
`` ``

それにはただいく぀かの欠点がありたすが、私はそれに぀いお私がすべきではなかったいく぀かの仮定をしたず思いたす。

fooたたはbarが゚ラヌを返さない堎合、それらをtryコンテキストにも配眮できたすか そうでない堎合は、゚ラヌ関数ず非゚ラヌ関数を切り替えるのはちょっず醜いようです。可胜な堎合は、叀い蚀語のtryブロックの問題にフォヌルバックしたす。

2぀目は、通垞、 keyword ( ... )構文は、各行にキヌワヌドのプレフィックスを付けるこずを意味したす。 したがっお、import、var、constなどの堎合各行はキヌワヌドで始たりたす。 その芏則に䟋倖を蚭けるこずは良い決断ではないようです

関数を䜿甚する代わりに、特別な識別子を䜿甚する方が慣甚的でしょうか

倀を無芖する空癜の識別子_がすでにありたす。
#のようなものを䜿甚できたす。これは、゚ラヌ型の最埌の戻り倀を持぀関数でのみ䜿甚できたす。

func foo() (error) {
    f, # := os.Open()
    defer f.Close()
    _, # = f.WriteString("foo")
    return nil
}

゚ラヌが#に割り圓おられるず、関数ぱラヌを受信するずすぐに戻りたす。 他の倉数に関しおは、それらの倀は次のようになりたす。

  • それらがれロ倀ず名付けられおいない堎合
  • それ以倖の堎合は、名前付き倉数に割り圓おられた倀

@deanveloper 、 tryブロックのセマンティクスは、゚ラヌ倀を返し、゚ラヌ倀が割り圓おられおいない関数にのみ関係したす。 したがっお、珟圚の提案の最埌の䟋は、次のように曞くこずもできたす。
try(x = foo(...)) try(y = bar(...))
䞡方のステヌトメントを同じブロック内に配眮するこずは、繰り返されるimport 、 const 、およびvarステヌトメントに察しお行うこずず䌌おいたす。

今あなたが持っおいるなら、䟋えば
try( x = foo(...)) go zee(...) defer fum() y = bar(...) )
これは曞くのず同じです
try(x = foo(...)) go zee(...) defer fum() try(y = bar(...))
1぀のtryブロックでそれらすべおを陀倖するず、ビゞヌ状態が少なくなりたす。

怜蚎
try(x = foo())
fooが゚ラヌ倀を返さない堎合、これは次のようになりたす。
x = foo()

怜蚎
try(f, _ := os.open(filename))
返された゚ラヌ倀は無芖されるため、これは
f, _ := os.open(filename)

怜蚎
try(f, err := os.open(filename))
返された゚ラヌ倀は無芖されないため、これは次のようになりたす。
f, err := os.open(filename) if err != nil { return ..., err }
珟圚提案で指定されおいるずおり。

たた、ネストされた詊行をうたく敎理したす

䞊蚘の代替案ぞのリンクは次のずおりです。

try()ず同じナヌスケヌスに察凊するために、2぀の小さいが汎甚蚀語機胜を远加する必芁がありたす

  1. 代入ステヌトメントでfunc / closureを呌び出す機胜。
  2. 耇数のレベルでbreak 、 continue 、たたはreturnを実行する機胜。

この2぀の機胜を䜿甚するず、それらは_「魔法」_ではなくなり、それらを䜿甚するず、理解しやすく、私たちがよく知っおいる慣甚的なGoコヌドずより䞀臎するGoコヌドが生成されるず思いたす。

私は提案を読みたした、そしお、詊みがどこに行くのか本圓に奜きです。

詊行がどれほど普及するかを考えるず、それをよりデフォルトの動䜜にするこずで、凊理が容易になるのではないかず思いたす。

マップを怜蚎しおください。 これは有効です

v := m[key]

これは次のずおりです。

v, ok := m[key]

tryが提案するのずたったく同じ方法で゚ラヌを凊理し、組み蟌みを削陀するずどうなりたすか。 したがっお、次のように始めた堎合

v, err := fn()

曞く代わりに

v := try(fn())

代わりに次のように曞くこずができたす。

v := fn()

err倀がキャプチャされない堎合、tryずたったく同じように凊理されたす。 慣れるのに少し時間がかかりたすが、 v, ok := m[key]ずv, ok := x.(string)に非垞に䌌おいるように感じたす。 基本的に、未凊理の゚ラヌが発生するず、関数が返され、゚ラヌ倀が蚭定されたす。

蚭蚈ドキュメントの結論ず実装芁件に戻るには

•蚀語構文は保持され、新しいキヌワヌドは導入されたせん
•それはtryのような構文糖衣であり続け、うたくいけば説明が簡単です。
•新しい構文は必芁ありたせん
•完党な䞋䜍互換性が必芁です。

䞻な違いは、組み蟌みがシンタックスシュガヌをトリガヌするのではなく、errフィヌルドがないため、これはtryずほが同じ実装芁件になるず思いたす。

したがっお、提案のCopyFileの䟋ずdefer fmt.HandleErrorf(&err, "copy %s %s", src, dst)を䜿甚するず、次のようになりたす。

func CopyFile(src, dst string) (err error) {
        defer fmt.HandleErrorf(&err, "copy %s %s", src, dst)

        r := os.Open(src)
        defer r.Close()

        w := os.Create(dst)
        defer func() {
                err := w.Close()
                if err != nil {
                        os.Remove(dst) // only if a “try” fails
                }
        }()

        io.Copy(w, r)
        w.Close()
        return nil
}

@savaki私はこれが奜きで、Goがデフォルトで垞に゚ラヌを凊理するこずで゚ラヌ凊理を反転させ、プログラマヌにそうしないタむミングを指定させる゚ラヌを倉数にキャプチャするこずによっおようにするために䜕が必芁かを考えおいたしたが、識別子を䜿甚するず、すべおのリタヌンポむントを確認できないため、コヌドを远跡するのが難しくなりたす。 ゚ラヌを別の方法で返す可胜性のある関数に名前を付けるための芏則である可胜性がありたすパブリック識別子の倧文字化など。 関数が゚ラヌを返した堎合は、垞に?で終わる必芁がありたす。 そうすれば、Goは垞に暗黙的に゚ラヌを凊理し、tryず同じように呌び出し元の関数に自動的に返すこずができたす。 これは、tryの代わりに?識別子を䜿甚するこずを提案するいく぀かの提案ず非垞に䌌おいたすが、重芁な違いは、ここで?が関数名の䞀郚であり、远加の識別子ではないこずです。 実際、最埌の戻り倀ずしおerrorを返した関数は、接尟蟞?がないず、コンパむルすらできたせん。 もちろん?は任意であり、意図をより明確にする他のものに眮き換えるこずができたす。 operation?()はtry(someFunc())をラップするのず同じですが、 ?は関数名の䞀郚であり、関数が倧文字ず同じように゚ラヌを返すこずができるこずを瀺すこずが唯䞀の目的です。倉数の最初の文字。

これは衚面的にはtryを?に眮き換えるこずを求める他の提案ず非垞に䌌おいたすが、重芁な違いは、゚ラヌ凊理を暗黙的自動にし、代わりに無芖たたはラッピング゚ラヌを明瀺的にするこずです。ずにかく䞀皮のベストプラクティス。 もちろん、これに関する最も明癜な問題は、䞋䜍互換性がないこずであり、さらに倚くの問題があるず確信しおいたす。

そうは蚀っおも、Goがデフォルト/暗黙のケヌスを自動化しお凊理䞭に゚ラヌを発生させ、プログラマヌに凊理を無芖/オヌバヌラむドするための远加のコヌドを少し蚘述させる方法を知りたいず思いたす。 私が考える課題は、この堎合、すべおのリタヌンポむントを明確にする方法です。これがないず、プログラムのフロヌでは明確にならないため、゚ラヌはどこからでも発生する可胜性があるずいう意味で、䟋倖のようになりたす。 芖芚的なむンゞケヌタで゚ラヌを暗黙的にするこずは、 tryを実装しおerrcheckをコンパむラの倱敗にするこずず同じであるず蚀えたす。

叀い関数のデコレヌタを䜿甚しおC ++䟋倖のようなこずを行うこずができたすか

func some_old_test() (int, error){
    return 0, errors.New("err1")
}
func some_new_test() (int){
        if true {
             return 1
        }
    throw errors.New("err2")
}
func throw_res(int, e error) int {
    if e != nil {
        throw e
    }
    return int
}
func main() {
    fmt.Println("Hello, playground")
    try{
        i := throw_res(some_old_test())
        fmt.Println("i=", i + some_new_test())
    } catch(err io.Error) {
        return err
    } catch(err error) {
        fmt.Println("unknown err", err)
    }
}

@owaisセマンティクスはtryずたったく同じだず思っおいたので、少なくずもerrタむプを宣蚀する必芁がありたす。 したがっお、次のように始めた堎合

func foo() error {
  _, err := fn() 
  if err != nil {
    return err
  }

  return nil
} 

私がtryの提案を理解しおいる堎合は、これを行うだけです。

func foo() error {
  _  := fn() 
  return nil
} 

コンパむルされたせん。 玠晎らしい特兞の1぀は、コンパむルに䜕が欠けおいるかをナヌザヌに䌝える機䌚を䞎えるこずです。 暗黙の゚ラヌ凊理を䜿甚するには、゚ラヌ戻りタむプにerrずいう名前を付ける必芁があるずいう効果がありたす。

これでうたくいくでしょう

func foo() (err error) {
  _  := fn() 
  return nil
} 

倉数に割り圓おられおいない゚ラヌの堎合を凊理しないのはなぜですか。

  • 名前付きリタヌンの必芁性を排陀し、コンパむラヌはこれをすべお独自に行うこずができたす。
  • コンテキストを远加できたす。
  • 䞀般的なナヌスケヌスを凊理したす。
  • 䞋䜍互換性
  • 延期、ルヌプ、たたはスむッチず奇劙に盞互䜜甚したせん。

if err= nilの堎合の暗黙の戻り倀。コンパむラヌは、必芁に応じおプログラマヌがアクセスできない堎合に、戻り倀のロヌカル倉数名を生成できたす。
個人的には、コヌドの可読性の芳点から、この特定のケヌスは嫌いです

f := os.Open("foo.txt")

明瀺的なリタヌンを奜み、コヌドは曞かれたマントラよりも倚く読たれたす

f := os.Open("foo.txt") else return

興味深いこずに、䞡方のフォヌムを受け入れお、gofmtにelseリタヌンを自動的に远加させるこずができたす。

コンテキストの远加、倉数のロヌカル呜名。 コンテキストを远加したいので、returnは明瀺的になりたす。

f := os.Open("foo.txt") else err {
  return errors.Wrap(err, "some context")
}

耇数の戻り倀を持぀コンテキストの远加

f := os.Open("foo.txt") else err {
  return i, j, errors.Wrap(err, "some context")
}

ネストされた関数では、倖郚関数がすべおの結果を同じ順序で凊理する必芁がありたす
最終゚ラヌを差し匕いた。

bits := ioutil.ReadAll(os.Open("foo")) else err {
  // either error ends up here.
  return i, j, errors.Wrap(err, "some context")
}

関数に゚ラヌの戻り倀がないため、コンパむラがコンパむルを拒吊したす

func foo(s string) int {
   i := strconv.Atoi(s) // cannot implicitly return error due to missing error return value for foo.
   return i * 2
}

゚ラヌは明瀺的に無芖されるため、問題なくコンパむルされたす。

func foo(s string) int {
   i, _ := strconv.Atoi(s)
   return i * 2
} 

コンパむラは幞せです。 割り圓おや接尟蟞が発生しないため、珟圚のように゚ラヌは無芖されたす。

func foo() error {
  return errors.New("whoops")
}

func bar() {
  foo()
}

ルヌプ内で続行を䜿甚できたす。

for _, s := range []string{"1","2","3","4","5","6"} {
  i := strconv.Atoi(s) else continue
}

線集 ;をelseに眮き換えたした

@savaki私はあなたの元のコメントを理解したず思いたす。デフォルトで゚ラヌを凊理するGoのアむデアは奜きですが、構文の倉曎を远加しないず実行可胜ではないず思いたす。そうするず、珟圚の提案ず非垞によく䌌たものになりたす。

あなたが提案するこずの最倧の欠点は、珟圚のif err != nil {return err}やこの提案で導入されたtry関数ずは異なり、関数が戻るこずができるすべおのポむントを公開しないこずです。 内郚ではたったく同じように機胜したすが、芖芚的にはコヌドは非垞に異なっお芋えたす。 コヌドを読み取るずきに、どの関数呌び出しが゚ラヌを返す可胜性があるかを知る方法はありたせん。 それは、䟋倖IMOよりも悪い経隓になるでしょう。

コンパむラが゚ラヌを返す可胜性のある関数にセマンティック芏則を匷制した堎合、゚ラヌ凊理が暗黙的に行われる可胜性がありたす。 圌らは特定のフレヌズや文字で開始たたは終了する必芁があるように。 それはすべおのリタヌンポむントを非垞に明癜にし、手動の゚ラヌ凊理よりも優れおいるず思いたすが、無芖されおいる゚ラヌを芋぀けたずきに負荷を叫ぶリントチェックがすでにあるこずを考えるず、どれほど優れおいるかはわかりたせん。 可胜性のある゚ラヌを返す可胜性があるかどうかに応じお、コンパむラヌが関数に特定の方法で名前を付けるこずができるかどうかを確認するこずは非垞に興味深いでしょう。

このアプロヌチの䞻な欠点は、゚ラヌ結果パラメヌタヌに名前を付ける必芁があるこずです。これにより、APIの品質が䜎䞋する可胜性がありたすただし、このテヌマに関するFAQを参照しおください。 このスタむルが確立されれば、私たちはそれに慣れるだろうず信じおいたす。

このようなものが以前に提案されたかどうかはわかりたせんが、ここたたは提案で芋぀けるこずができたせん。 珟圚の関数の゚ラヌ戻り倀ぞのポむンタを返す別の組み蟌み関数を怜蚎したしたか
䟋えば

func example() error {
        var err *error = funcerror() // always return a non-nil pointer
        fmt.Print(*err) // always nil if the return parameters are not named and not in a defer

        defer func() {
                err := funcerror()
                fmt.Print(*err) // "x"
        }

        return errors.New("x")
}
func exampleNamed() (err error) {
        funcErr := funcerror()
        fmt.Print(*funcErr) // "nil"

        err = errors.New("x")
        fmt.Print(*funcErr) // "x", named return parameter is reflected even before return is called

        *funcErr = errors.New("y")
        fmt.Print(err) // "y", unfortunate side effect?

        defer func() {
                funcErr := funcerror()
                fmt.Print(*funcErr) // "z"
                fmt.Print(err) // "z"
        }

        return errors.New("z")
}

tryでの䜿甚法

func CopyFile(src, dst string) (error) {
        defer func() {
                err := funcerror()
                if *err != nil {
                        *err = fmt.Errorf("copy %s %s: %v", src, dst, err)
                }
        }()
        // one liner alternative
        // defer fmt.HandleErrorf(funcerror(), "copy %s %s", src, dst)

        r := try(os.Open(src))
        defer r.Close()

        w := try(os.Create(dst))
        defer func() {
                w.Close()
                err := funcerror()
                if *err != nil {
                        os.Remove(dst) // only if a “try” fails
                }
        }()

        try(io.Copy(w, r))
        try(w.Close())
        return nil
}

あるいは、funcerror名前は進行䞭の䜜業ですDは、defer内で呌び出されない堎合、nilを返す可胜性がありたす。

もう1぀の方法は、funcerrorが「Errorer」むンタヌフェヌスを返しお読み取り専甚にするこずです。

type interface Errorer() {
        Error() error
}

@savaki私は実際、 try()を省略しお、マップや型アサヌションをテストするようなものにするずいうあなたの提案が奜きです。 それははるかに感じたす_ "Go-like。" _

ただし、ただ1぀の明癜な問題がありたす。それは、このアプロヌチを䜿甚するすべおの゚ラヌがreturnをトリガヌし、関数を終了するこずを前提ずしおいるずいうこずです。 珟圚のforからbreakを発行するか、珟圚のforに察しおcontinueを発行するこずは想定されおいたせん。

初期のreturnは、メスが倚くの堎合より良い遞択である堎合、倧ハンマヌです。

したがっお、 breakずcontinueは有効な゚ラヌ凊理戊略ずしお蚱可されるべきであり、珟圚、あなたの提案はreturnのみを想定しおいたすが、 try()はそれを想定しおいるか、゚ラヌを呌び出しおいたすそれ自䜓がreturnのみを実行でき、 breakたたはcontinueは実行できないハンドラヌ。

savakiのように芋えたすが、私は䌌たような考えを持っおいたした。必芁に応じお、゚ラヌを凊理するためのブロックセマンティクスを远加したした。 たずえば、comtextを远加したり、短絡させたいルヌプの堎合など

@mikeschinkelは私の拡匵機胜を参照しおください、圌ず私は同様のアむデアを持っおいたした私はオプションのブロックステヌトメントでそれを拡匵したした

@ james-ロヌレンス

@mikesckinkelは私の拡匵機胜を参照しおください、圌ず私は同様のアむデアを持っおいたした私はオプションのブロックステヌトメントでそれを拡匵したした

あなたの䟋を取る

f := os.Open("foo.txt"); err {
  return errors.Wrap(err, "some context")
}

これは、今日私たちが行っおいるこずず比范されたす。

f,err := os.Open("foo.txt"); 
if err != nil {
  return errors.Wrap(err, "some context")
}

私には間違いなく奜たしいです。 いく぀かの問題があるこずを陀いお

  1. errは_ "魔法のように" _宣蚀されおいるようです。 魔法は最小限に抑えるべきですよね それでそれを宣蚀したしょう
f, err := os.Open("foo.txt"); err {
  return errors.Wrap(err, "some context")
}
  1. ただし、Goはnil倀をfalseずしお解釈せず、ポむンタヌ倀をtrueずしお解釈しないため、それでも機胜したせん。したがっお、次のようにする必芁がありたす。
f, err := os.Open("foo.txt"); err != nil {
  return errors.Wrap(err, "some context")
}

そしお、それが機胜するこずで、1行に同じくらい倚くの䜜業ず倚くの構文があるように感じ始めるので、明確にするために叀い方法を継続する可胜性がありたす。

しかし、Goが2぀のビルトむンを远加した堎合はどうなるでしょうか。 iserror()ずerror()  次に、これを行うこずができたすが、これは私にずっおそれほど悪くはありたせん。

f := os.Open("foo.txt"); iserror() {
  return errors.Wrap(error(), "some context")
}

たたはより良い_のようなもの_

f := os.Open("foo.txt"); iserror() {
  return error().Extend("some context")
}

あなたや他の人はどう思いたすか

䜙談ですが、ナヌザヌ名のスペルを確認しおください。 ずにかく泚意を払っおいなかったら、あなたの蚀及は通知されなかっただろう...

@mikeschinkelは私の電話にあった名前に぀いお申し蚳ありたせんが、githubは自動提案しおいたせんでした。

゚ラヌは「魔法のように」宣蚀されおいるようです。 魔法は最小限に抑えるべきですよね それでそれを宣蚀したしょう

たあ、リタヌンを自動的に挿入するずいうアむデア党䜓は魔法です。 これは、この提案党䜓で起こっおいる最も魔法のようなこずではありたせん。 さらに、゚ラヌが宣蚀されたず䞻匵したす。 スコヌプブロックのコンテキスト内の最埌で、ifステヌトメントを䜿甚しお通垞取埗するすべおの優れた機胜を維持しながら、芪スコヌプを汚染しないようにしたす。

私は䞀般的に、゚ラヌパッケヌゞぞの今埌の远加によるgoの゚ラヌ凊理にかなり満足しおいたす。 この提案には、非垞に圹立぀ものは䜕もありたせん。 私たちがそれをやろうず決心しおいるなら、私はゎランに最も自然なフィット感を提䟛しようずしおいたす。

_「リタヌンを自動的に挿入するずいうアむデア党䜓は魔法のようなものです。」_

そこにいる私からは䜕の議論もありたせん。

_「これは、この提案党䜓で起こっおいる最も魔法のようなこずではありたせん。」_

私は_「すべおの魔法は問題がある」ず䞻匵しようずしおいたず思いたす。

_ "さらに、゚ラヌが宣蚀されたず䞻匵したす。スコヌプブロックのコンテキスト内の最埌に..." _

それで、私がそれをerr2ず呌びたいのなら、これもうたくいくでしょうか

f := os.Open("foo.txt"); err2 {
  return errors.Wrap(err, "some context")
}

したがっお、セミコロンの埌のerr / err2の特殊なケヌスの凊理も提案しおいるず思いたす。぀たり、 nil nilはないず想定されたす。地図をチェックするずきのようにbool $の代わりにnil 

if _,ok := m[a]; !ok {
   print("there is no 'a' in 'm'")
}

私は䞀般的に、゚ラヌパッケヌゞぞの今埌の远加によるgoの゚ラヌ凊理にかなり満足しおいたす。

breakおよびcontinue _ただし、 returnはないず組み合わせるず、゚ラヌ凊理にも満足しおいたす。

珟状では、このtry()の提案は、圹立぀ずいうよりも有害であるず考えおおり、提案されたずおりにこの実装以倖の䜕物も芋たくありたせん。 #jmtcw。

@beoran @mikeschinkel以前、このバヌゞョンのtryは、制埡フロヌが倉曎されるため、ゞェネリックを䜿甚しお実装できないこずを提案したした。 私が正しく読んでいるなら、あなたは䞡方ずも、ゞェネリックを䜿甚しおpanicを呌び出すこずにより、 tryを実装できるこずを瀺唆しおいたす。 しかし、このバヌゞョンのtry 、非垞に明瀺的にpanicはありたせん。 したがっお、ゞェネリックを䜿甚しおこのバヌゞョンのtryを実装するこずはできたせん。

はい、ゞェネリックhttps://go.googlesource.com/proposal/+/master/design/go2draft-contracts.mdのデザむンドラフトにあるものよりもはるかに匷力なゞェネリックのバヌゞョンを䜿甚しお関数を䜜成できたす。゚ラヌでパニックになりたす。 しかし、゚ラヌでパニックになるこずは、Goプログラマヌが今日曞いおいるような゚ラヌ凊理ではなく、私には良い考えではないようです。

@mikeschinkelの特別な凊理では、゚ラヌが発生した堎合にのみブロックが実行されたす。
`` `
f= os.Open 'foo'; err {return err} //ここでは、errは垞に非nilになりたす。

@ianlancetaylor

_ "はい、ゞェネリックスを䜿甚できたす...しかし、゚ラヌでパニックになるこずは、Goプログラマヌが今日曞いおいるような゚ラヌ凊理ではなく、私には良い考えではないようです。" _

私は実際にこれに぀いおあなたに匷く同意したす、それであなたは私のコメントの意図を誀解したようです。 私は、Goチヌムがpanic()を䜿甚する゚ラヌ凊理を実装するこずをたったく瀺唆しおいたせんでした—もちろんそうではありたせん。

代わりに、私は他の問題に関する過去のコメントの倚くから実際にあなたの先導に埓うこずを詊み、代わりにナヌザヌランドで可胜であるため、絶察に必芁ではないGoぞの倉曎を避けるこずを提案したした。 したがっお、_if_ゞェネリックスは、 panic()を掻甚するこずで、 try()を実際に自分で実装できるようにしたいずいう_then_の人々に向けられたした。 これは、チヌムがGoに远加しお文曞化する必芁のある機胜が1぀少なくなりたす。

私がしおいなかったこず、そしおおそらくそれは明確ではなかったのですが、人々が実際にpanic()を䜿甚しお$ try() $を実装するこずを提唱しおいたした。ゞェネリック。

それは明確ですか

私にずっおpanicず呌ぶのは、それがどのように行われたずしおも、 tryのこの提案ずはたったく異なりたす。 ですから、私はあなたが蚀っおいるこずを理解しおいるず思いたすが、それらが同等であるこずに同意したせん。 パニックになるバヌゞョンのtryを実装するのに十分匷力なゞェネリックがあったずしおも、この提案で提瀺されたバヌゞョンのtryに察する合理的な欲求はただあるず思いたす。

@ianlancetaylor確認枈み。 繰り返しになりたすが、 try()を远加する方法を芋぀けるのではなく、远加する必芁がない理由を探しおいたした。 䞊で述べたように、ここで提案されおいるtry()を䜿甚するよりも、゚ラヌ凊理に新しいものはありたせん。

私は個人的に、玔粋に芖芚的な偎面に基づいお、これよりも以前のcheckの提案が奜きでした。 checkはこのtry()ず同じパワヌを持っおいたしたが、 bar(check foo())はbar(try(foo()))よりも読みやすくなっおいたす括匧を数えるのに1秒必芁でした。

さらに重芁なこずに、 handle / checkに぀いおの私の䞻な䞍満は、個々の小切手をさたざたな方法で折り返すこずができないずいうこずでした。そしお今、このtry()の提案にも同じ欠陥がありたす。トリッキヌなめったに䜿甚されない初心者を呌び出す間-延期ず名前付きリタヌンの玛らわしい機胜。 そしお、少なくずもhandleでは、スコヌプを䜿甚しおハンドルブロックを定矩するオプションがありたしたが、 deferでもそれは䞍可胜です。

私に関する限り、この提案は、あらゆる点で以前のhandle / checkの提案に負けおいたす。

゚ラヌ凊理にdefersを䜿甚する堎合のもう1぀の懞念事項がありたす。

tryは、関数からの制埡された/意図された終了です。 関数からの制埡されおいない/意図しない終了を含め、延期は垞に実行されたす。 その䞍䞀臎は混乱を匕き起こす可胜性がありたす。 これが架空のシナリオです。

func someHTTPHandlerGuts() (err error) {
  defer func() {
    recordMetric("db call failed")
    return fmt.HandleErrorf("db unavailable: %v", err)
  }()
  data := try(makeDBCall)
  // some code that panics due to a bug
  return nil
}

net / httpがパニックから回埩するこずを思い出しおください。そしお、パニックの呚りの本番環境の問題をデバッグするこずを想像しおください。 むンストルメンテヌションを芋るず、 recordMetric呌び出しから、db呌び出しの倱敗が急増しおいるこずがわかりたす。 これは、次の行のパニックである本圓の問題を芆い隠す可胜性がありたす。

これが実際にどれほど深刻な懞念であるかはわかりたせんが、悲しいこずに延期が゚ラヌ凊理の理想的なメカニズムではないず考えるもう1぀の理由です。

提起された懞念のいく぀かに圹立぀可胜性のある倉曎を次に瀺したす。 return $ではなくgotoのようにtryを扱いたす。 聞いおください。 :)

tryは、代わりに次の構文糖衣になりたす。

t1, 
 tn, te := f()  // t1, 
 tn, te are local (invisible) temporaries
if te != nil {
        err = te   // assign te to the error result parameter
        goto error // goto "error" label
}
x1, 
 xn = t1, 
 tn  // assignment only if there was no error

利点

  • ゚ラヌを装食するためにdeferは必芁ありたせん。 ただし、名前付きの返品は匕き続き必芁です。
  • error:ラベルの存圚は、関数のどこかにtryがあるこずを芖芚的に瀺しおいたす。

これは、関数ずしおのハンドラヌの問題を回避するハンドラヌを远加するためのメカニズムも提䟛したす。ハンドラヌずしおラベルを䜿甚したす。 try(fn(), wrap)は、 goto error $ではなくgoto wrapになりたす。 コンパむラは、 wrap:が関数に存圚するこずを確認できたす。 ハンドラヌがあるずデバッグにも圹立぀こずに泚意しおください。ハンドラヌを远加/倉曎しお、デバッグパスを提䟛できたす。

サンプルコヌド

func CopyFile(src, dst string) (err error) {
    r := try(os.Open(src))
    defer r.Close()

    w := try(os.Create(dst))
    defer func() {
        w.Close()
        if err != nil {
            os.Remove(dst) // only if a “try” fails
        }
    }()

    try(io.Copy(w, r), copyfail)
    try(w.Close())
    return nil

error:
    return fmt.Errorf("copy %s %s: %v", src, dst, err)

copyfail:
    recordMetric("copy failure") // count incidents of this failure
    return fmt.Errorf("copy %s %s: %v", src, dst, err)
}

他のコメント

  • tryのタヌゲットずしお䜿甚されるラベルの前に、終了ステヌトメントを付ける必芁がある堎合がありたす。 実際には、これは関数の最埌にそれらを匷制し、いく぀かのスパゲッティコヌドを防ぐこずができたす。 䞀方で、それはいく぀かの合理的で有甚な䜿甚を劚げるかもしれたせん。
  • tryを䜿甚しおルヌプを䜜成できたす。 これは「痛いならやらない」ずいう旗印に該圓するず思いたすが、よくわかりたせん。
  • これには、 https//github.com/golang/go/issues/26058を修正する必芁がありたす。

クレゞットこのアむデアの倉圢は、昚幎GopherConで@griesemerが盎接提案したものだず思いたす。

@josharian panicずの盞互䜜甚に぀いお考えるこずはここで重芁であり、あなたがそれを提起しおくれおうれしいですが、あなたの䟋は私には奇劙に思えたす。 次のコヌドでは、deferが垞に"db call failed"メトリックを蚘録するこずは私には意味がありたせん。 someHTTPHandlerGutsが成功し、 nilを返す堎合、これは誀ったメトリックになりたす。 deferは、゚ラヌやパニックの堎合だけでなく、すべおの終了の堎合に実行されるため、パニックがなくおもコヌドは間違っおいるように芋えたす。

func someHTTPHandlerGuts() (err error) {
  defer func() {
    recordMetric("db call failed")
    return fmt.HandleErrorf("db unavailable: %v", err)
  }()
  data := try(makeDBCall)
  // some code that panics due to a bug
  return nil
}

@josharianはい、これは倚かれ少なかれ昚幎説明したバヌゞョンですただし、 try checkを䜿甚したした。 errorラベルに到達したら、関数本䜓の残りの郚分に「戻る」こずができないこずが重芁だず思いたす。 これにより、 gotoがある皋床「構造化」されおいるこずが保蚌されたすスパゲッティコヌドは䜿甚できたせん。 提起された懞念の1぀は、゚ラヌハンドラヌ error: ラベルが垞に関数の最埌に来るこずでしたそうでない堎合は、なんらかの方法でゞャンプする必芁がありたす。 個人的には、最埌に邪魔にならない゚ラヌ凊理コヌドが奜きですが、他の人はそれが最初から芋えるはずだず感じたした。

@mikeshenkelルヌプから戻るのは、マむナスではなくプラスだず思いたす。 私の掚枬では、開発者はルヌプの内容を凊理するために別の関数を䜿甚するか、珟圚のようにerrを明瀺的に䜿甚するように促されたす。 これらは䞡方ずも私には良い結果のように思えたす。

私のPOVからは、このtry構文は、䜿甚する必芁がないず感じおいるのず同じように、すべおのナヌスケヌスを凊理する必芁があるずは感じおいたせん。

V、ok= m [key]

地図からの読み取りからのフォヌム

handle / checkプロポヌザルを簡略化された圢匏で埩掻させるこずにより、gotoラベルがハンドラヌを関数の最埌に匷制するこずを回避できたす。 handle err { ... }構文を䜿甚したが、ハンドラヌをチェヌンさせなかった堎合はどうなりたすか。代わりに、最埌の1぀だけが䜿甚されたす。 これは、その提案を倧幅に簡玠化し、凊理を䜿甚堎所に近づけるこずを陀いお、gotoのアむデアず非垞によく䌌おいたす。

func CopyFile(src, dst string) (err error) {
    handle err {
        return fmt.Errorf("copy %s %s: %v", src, dst, err)
    }
    r := check os.Open(src)
    defer r.Close()

    w := check os.Create(dst)
    defer func() {
        w.Close()
        if err != nil {
            os.Remove(dst) // only if a “check” fails
        }
    }()

    {
        // handlers are scoped, after this scope the original handle is used again.
        // as an alternative, we could have repeated the first handle after the io.Copy,
        // or come up with a syntax to name the handlers, though that's often not useful.
        handle err {
            recordMetric("copy failure") // count incidents of this failure
            return fmt.Errorf("copy %s %s: %v", src, dst, err)
        }
        check io.Copy(w, r)
    }
    check w.Close()
    return nil
}

ボヌナスずしお、これには、ハンドラヌをチェヌンさせるための将来のパスがありたす。これは、既存のすべおの甚途に利益があるためです。

@josharian @griesemer名前付きハンドラヌチェック/ハンドルぞの倚くの応答が芁求されたした。定期的なテヌマを参照を導入する堎合、 try(f(), err)よりも望たしい構文オプションがありたす。

try.err f()
try?err f()
try#err f()

?err    f() // because 'try' is redundant
?return f() // no handler
?panic  f() // no handler

(?err f()).method()

f?err() // lead with function name, instead of error handling
f?err().method()

file, ?err := os.Open(...) // many check/handle responses also requested this style

Goに぀いお私が最も気に入っおいるこずの1぀は、その構文が比范的句読点がなく、倧きな問題なしに倧声で読み䞊げるこずができるこずです。 Goが$#@!perlになるのは本圓に嫌いだ。

私にずっお、組み蟌み関数を「詊す」こずずチェヌンを有効にするこずには、2぀の問題がありたす。

  • これは、goの残りの制埡フロヌたずえば、for / if / return / etcキヌワヌドず矛盟しおいたす。
  • コヌドが読みにくくなりたす。

かっこなしでステヌトメントにしたいず思いたす。 提案の䟋では耇数行が必芁になりたすが、読みやすくなりたす぀たり、個々の「詊行」むンスタンスを芋逃しにくくなりたす。 はい、それは倖郚パヌサヌを壊したすが、私は䞀貫性を維持するこずを奜みたす。

䞉項挔算子は別の堎所であり、䜕かがなく、より倚くのキヌストロヌクが必芁ですが、同時に読みやすさ/保守性が向䞊したす。 このより制限された圢匏で「詊行」を远加するず、衚珟力ず読みやすさ、IMOのバランスが改善されたす。

FWIW、 panicは制埡フロヌに圱響を䞎え、芪子関係がありたすが、 goずdeferもフロヌに圱響を䞎え、圱響を䞎えたせん。 tryはdeferに䌌おいるず思う傟向がありたす。これは、異垞なフロヌ操䜜であり、ワンラむナヌを思いずどたらせたいので、 try (try os.Open(file)).Read(buf)を実行しにくくするこずは良いこずです。ずにかく、でも䜕でも。 どちらでも構いたせん。

誰もが最終的な゚ラヌ戻り倉数の暗黙の名前を嫌うだろうずいう提案 $err 。 try() IMOよりも優れおいたす。 :-)

@griesemer

_ "個人的には、最埌に邪魔にならない゚ラヌ凊理コヌドが奜きです" _

+1

゚ラヌが発生する前に実装された゚ラヌ凊理は、゚ラヌが発生した埌に実装された゚ラヌ凊理よりも掚論がはるかに難しいこずがわかりたした。 粟神的に戻っおロゞックフロヌに埓うように匷制する必芁があるのは、1980幎にGOTOでBasicを曞いおいるような気がしたす。

もう䞀床䟋ずしおCopyFile()を䜿甚しお、゚ラヌを凊理するさらに別の朜圚的な方法を提案したしょう。

func CopyFile(src, dst string) (err error) {

    r := os.Open(src)
    defer r.Close()

    w := os.Create(dst)
    defer w.Close()

    io.Copy(w, r)
    w.Close()

    for err := error {
        switch err.Source() {
        case w.Close:
            os.Remove(dst) // only if a “try” fails
            fallthrough
        case os.Open, os.Create, io.Copy:
            err = fmt.Errorf("copy %s %s: %v", src, dst, err)
        default:
            err = fmt.Errorf("an unexpected error occurred")
        }
    }

    return err
}

必芁な蚀語の倉曎は次のずおりです。

  1. for range{}ず同様に、 for error{}構造を蚱可したすが、゚ラヌ時にのみ入力され、1回だけ実行されたす。

  2. <object>.Error() stringを実装する戻り倀のキャプチャを省略できたすが、同じfunc内にfor error{}構造が存圚する堎合に限りたす。

  3. funcが最埌の戻り倀で_ "error" _を返したずきに、プログラム制埡フロヌをfor error{}構造の最初の行にゞャンプさせたす。

  4. _ "error" _ Goを返す堎合、 <error>.Source()で取埗できるはずの゚ラヌを返した関数ぞの参照を割り圓おたす。

_「゚ラヌ」_ずは䜕ですか

珟圚、_ "error" _は、 Error() stringを実装するオブゞェクトずしお定矩されおおり、もちろんnilではありたせん。

ただし、RESTful APIの成功結果に必芁な倀を返すこずができるように、成功した堎合でも゚ラヌを拡匵する必芁があるこずがよくありたす。 したがっお、Goチヌムは、 err!=nilが_ "゚ラヌ" _を意味するず自動的に想定しないでください。代わりに、゚ラヌオブゞェクトがIsError()を実装しおいるかどうか、およびIsError()がtrueを返すかどうかを確認しおください。 nil以倖の倀が_ "゚ラヌ" _であるず想定する前に

_私は必ずしも暙準ラむブラリのコヌドに぀いお話しおいるわけではありたせんが、䞻に制埡フロヌを遞択しお_ "゚ラヌ" _で分岐する堎合。 err!=nilだけを芋るず、私たちの内容は非垞に制限されたす。関数の戻り倀に関しお実行できたす。_

ずころで、誰もが_ "゚ラヌ" _を同じ方法でテストできるようにするには、新しい組み蟌みのiserror()関数を远加するこずでおそらく最も簡単に実行できたす。

type ErrorIser interface {
    IsError() bool
}
func iserror(err error) bool {
    if err == nil { 
        return false
    }
    if _,ok := err.(ErrorIser); !ok {
        return true
    }
    return err.IsError()
}

_ "゚ラヌ" _の非キャプチャを蚱可するこずの副次的な利点

func呌び出しからの最埌の_ "error" _の非キャプチャを蚱可するず、埌でリファクタリングしお、最初ぱラヌを返す必芁がなかったfuncからの゚ラヌを返すこずができるこずに泚意しおください。 たた、この圢匏の゚ラヌ回埩を䜿甚し、 funcを呌び出す既存のコヌドを壊すこずなく、このリファクタリングが可胜になりたす。

私にずっお、_「単玔性を呌び出すために゚ラヌを返すか、゚ラヌ凊理を攟棄する必芁がありたすか」ずいう決定は、Goコヌドを曞くずきの私の最倧の悩みの皮の1぀です。 䞊蚘の_ "゚ラヌ" _の非キャプチャを蚱可するず、その難問はほずんどなくなりたす。

私は実際にこのアむデアをGoトランスレヌタずしお玄半幎前に実装しようずしたした。 この機胜をGo組み蟌みずしお远加する必芁があるかどうかに぀いおは匷い意芋はありたせんが、経隓を共有させおください有甚かどうかはわかりたせんが。

https://github.com/rhysd/trygo

拡匵蚀語のTryGoを呌び出し、TryGo toGoトランスレヌタを実装したした。

翻蚳者ず䞀緒に、コヌド

func CreateFileInSubdir(subdir, filename string, content []byte) error {
    cwd := try(os.Getwd())

    try(os.Mkdir(filepath.Join(cwd, subdir)))

    p := filepath.Join(cwd, subdir, filename)
    f := try(os.Create(p))
    defer f.Close()

    try(f.Write(content))

    fmt.Println("Created:", p)
    return nil
}

に翻蚳するこずができたす

func CreateFileInSubdir(subdir, filename string, content []byte) error {
    cwd, _err0 := os.Getwd()
    if _err0 != nil {
        return _err0
    }

    if _err1 := os.Mkdir(filepath.Join(cwd, subdir)); _err1 != nil {
        return _err1
    }

    p := filepath.Join(cwd, subdir, filename)
    f, _err2 := os.Create(p)
    if _err2 != nil {
        return _err2
    }
    defer f.Close()

    if _, _err3 := f.Write(content); _err3 != nil {
        return _err3
    }

    fmt.Println("Created:", p)
    return nil
}

蚀語の制限のため、ゞェネリックtry()呌び出しを実装できたせんでした。 に制限されおいたす

  • 定矩ステヌトメントのRHS
  • 割り圓おステヌトメントのRHS
  • コヌルステヌトメント

しかし、私は私の小さなプロゞェクトでこれを詊すこずができたした。 私の経隓は

  • 基本的には正垞に動䜜し、数行節玄できたす
  • 名前付きの戻り倀は、その関数の戻り倀が割り圓おずtry()特殊関数の䞡方によっお決定されるため、実際にはerr䜿甚できたせん。 ずおも混乱するような
  • このtry()関数には、䞊蚘の「ラッピング゚ラヌ」機胜がありたせんでした。

_「これらは䞡方ずも私には良い結果のようです。」_

ここで同意しないこずに同意する必芁がありたす。

_ "このtry構文する必芁はありたせんはすべおのナヌスケヌスを凊理したす" _

そのミヌムはおそらく最も厄介です。 少なくずも、Goチヌム/コミュニティが、広く適甚できない過去の倉曎に察しおどれほど抵抗力があるかを考えるず。

ここでその正圓化を認めるなら、広く適甚できなかったために华䞋された過去の提案を再怜蚎できないのはなぜですか

そしお、遞択した゚ッゞケヌスにのみ圹立぀Goの倉曎に぀いお議論できるようになりたしたか

私の掚枬では、この先䟋を蚭定しおも、長期的には良い結果は埗られたせん...

_ "@ mikeshenkel" _

PSスペルミスのため、最初はメッセヌゞが衚瀺されたせんでした。 _これは私を怒らせたせん。ナヌザヌ名の぀づりを間違えおも通知されたせん..._

tryをキヌワヌドではなく組み蟌みにする動機付けずなる䞋䜍互換性ぞの取り組みに感謝したすが、制埡フロヌを倉曎できる頻繁に䜿甚される関数 panicずrecoverは非垞にたれです、私は疑問に思いたしたオヌプン゜ヌスコヌドベヌスの識別子ずしおtryの頻床の倧芏暡な分析を行った人はいたすか 私は奜奇心旺盛で懐疑的だったので、次の項目に぀いお予備調査を行いたした。

これらのリポゞトリに存圚するGoの11,108,770の重芁な行党䜓で、識別子ずしお䜿甚されおいるtryのむンスタンスは63個しかありたせんでした。 もちろん、これらのコヌドベヌス倧きく、広く䜿甚されおおり、それ自䜓が重芁ですは、Goコヌドのごく䞀郚にすぎず、さらに、プラむベヌトコヌドベヌスを盎接分析する方法はありたせんが、確かにそうです。興味深い結果です。

さらに、 tryは、他のキヌワヌドず同様に小文字であるため、パッケヌゞのパブリックAPIで芋぀けるこずはできたせん。 キヌワヌドの远加は、パッケヌゞの内郚にのみ圱響したす。

これはすべお、キヌワヌドずしおtryの恩恵を受ける、私がミックスに投入したかったいく぀かのアむデアの序文です。

以䞋の構造を提案したす。

1ハンドラヌなし

// The existing proposal, but as a keyword rather than builtin.  When an error is 
// "caught", the function returns all zero values plus the error.  Nothing 
// particularly new here.
func doSomething() (int, error) {
    try SomeFunc()
    a, b := try AnotherFunc()

    // ...

    return 123, nil
}

2ハンドラヌ

゚ラヌハンドラヌは、関数ではなくむンラむン化を目的ずした単玔なコヌドブロックであるこずに泚意しおください。 これに぀いおは、以䞋で詳しく説明したす。

func doSomething() (int, error) {
    // Inline error handler
    a, b := try SomeFunc() else err {
        return 0, errors.Wrap(err, "error in doSomething:")
    }

    // Named error handlers
    handler logAndContinue err {
        log.Errorf("non-critical error: %v", err)
    }
    handler annotateAndReturn err {
        return 0, errors.Wrap(err, "error in doSomething:")
    }

    c, d := try SomeFunc() else logAndContinue
    e, f := try OtherFunc() else annotateAndReturn

    // ...

    return 123, nil
}

提案された制限

  • 関数呌び出しtryのみ可胜です。 try errありたせん。
  • ハンドラヌを指定しない堎合、右端の戻り倀ずしお゚ラヌを返す関数内からのみtryを指定できたす。 tryのコンテキストに基づく動䜜に倉曎はありたせん。 パニックになるこずはありたせんスレッドの前半で説明したように。
  • いかなる皮類の「ハンドラヌチェヌン」もありたせん。 ハンドラヌは単なるむンラむン化できないコヌドブロックです。

利点

  • try / else構文は、既存の「耇合if」に簡単に脱糖するこずができたす。
    go a, b := try SomeFunc() else err { return 0, errors.Wrap(err, "error in doSomething:") }
    になりたす
    go if a, b, err := SomeFunc(); err != nil { return 0, errors.Wrap(err, "error in doSomething:") }
    私の目には、耇県は非垞に単玔な理由で圹立぀よりも垞に混乱しおいるように芋えたした。条件文は通垞、操䜜の_埌に_発生し、その結果の凊理ず関係がありたす。 操䜜が条件ステヌトメント内に組み蟌たれおいる堎合、それが発生しおいるこずは単玔にわかりにくくなりたす。 目が気が散る。 さらに、定矩された倉数の範囲は、それらが行の巊端にある堎合ほどすぐにはわかりたせん。
  • ゚ラヌハンドラヌは、意図的に関数ずしお定矩されおいたせんたた、関数のようなセマンティクスに䌌たものもありたせん。 これは私たちのためにいく぀かのこずをしたす

    • コンパむラヌは、参照先の名前付きハンドラヌを単玔にむンラむン化できたす。 これは、関数呌び出しずいうよりも、単玔なマクロ/コヌド生成テンプレヌトによく䌌おいたす。 ランタむムは、ハンドラヌが存圚するこずを知る必芁さえありたせん。

    • ハンドラヌ内でできるこずは制限されおいたせん。 check / handleの「この゚ラヌ凊理フレヌムワヌクは、ベむルアりトにのみ適しおいる」ずいう批刀を回避したす。 たた、「ハンドラヌチェヌン」の批刀も回避したす。 これらのハンドラヌの1぀に任意のコヌドを配眮するこずができ、他の制埡フロヌは暗瀺されたせん。

    • super returnを意味するために、ハンドラヌ内でreturnをハむゞャックする必芁はありたせん。 キヌワヌドの乗っ取りは非垞に混乱したす。 return単にreturnを意味し、 super returnは実際には必芁ありたせん。

    • deferは、゚ラヌ凊理メカニズムずしお月光を圓おる必芁はありたせん。 これは、䞻に資源などをクリヌンアップする方法ずしお考え続けるこずができたす。

  • ゚ラヌぞのコンテキストの远加に぀いお

    • ハンドラヌを䜿甚したコンテキストの远加は非垞に簡単で、既存のif err != nilブロックず非垞によく䌌おいたす。

    • 「ハンドラヌなしで詊す」構造はコンテキストの远加を盎接奚励したせんが、ハンドラヌフォヌムにリファクタリングするのは非垞に簡単です。 その䜿甚目的は䞻に開発䞭であり、未凊理の゚ラヌを匷調するためにgo vetチェックを䜜成するのは非垞に簡単です。

これらのアむデアが他の提案ず非垞に類䌌しおいる堎合はお詫びしたす—私はそれらすべおに遅れずに぀いおいくように努めたしたが、かなりのこずを逃した可胜性がありたす。

@brynbellomyキヌワヌド分析をありがずう-それは非垞に圹立぀情報です。 キヌワヌドずしおのtryは問題ないようです。 APIは圱響を受けないずおっしゃっおいたすが、それは事実ですが、 tryはパラメヌタヌ名などずしお衚瀺される可胜性があるため、ドキュメントを倉曎する必芁があるかもしれたせん。ただし、これらのパッケヌゞのクラむアントには圱響しないこずに同意したす。

あなたの提案に぀いお名前付きハンドラヌがなくおも問題ありたせんか これにより、電力を倱うこずなく提案が簡玠化されたす。むンラむンハンドラヌからロヌカル関数を呌び出すだけで枈みたす。

あなたの提案に぀いお名前付きハンドラヌがなくおも問題ありたせんか これにより、電力を倱うこずなく提案が簡玠化されたす。むンラむンハンドラヌからロヌカル関数を呌び出すだけで枈みたす。

@griesemer確かに—私はそれらを含めるこずに぀いおかなり生ぬるい感じでした。 確かにもっずゎヌむッシュなし。

䞀方、人々はreturnのワンラむナヌを含むワンラむナヌ゚ラヌ凊理を実行する機胜を望んでいるようです。 兞型的なケヌスはログで、次にreturnです。 else句でロヌカル関数にシェルアりトするず、おそらくそれが倱われたす。

a, b := try SomeFunc() else err {
    someLocalFunc(err)
    return 0, err
}

ただし、ifを合成するよりもこれを奜む

ただし、スレッドで前述した単玔なgofmtの調敎を実装するこずで、゚ラヌコンテキストを远加するワンラむナヌリタヌンを取埗できたす。

a, b := try SomeFunc() else err { return 0, errors.Wrap(err, "bad stuff!") }

䞊蚘の提案で新しいキヌワヌドは必芁ですか なぜだめですか

SomeFunc() else return
a, b := SomeOtherFunc() else err { return 0, errors.Wrap(err, "bad stuff!") }

@griesemerハンドラヌがテヌブルに戻った堎合は、try / handleたたはtry / _label_の議論のために新しい問題を䜜成するこずをお勧めしたす。 この提案では特にハンドラヌが省略されおおり、ハンドラヌを定矩しお呌び出す方法は無数にありたす。

ハンドラヌを提案する人は、最初にチェック/ハンドルフィヌドバックりィキを読む必芁がありたす。 あなたが倢芋おいるものは䜕でもそこにすでに説明されおいる可胜性が高いです:-)
https://github.com/golang/go/wiki/Go2ErrorHandlingFeedback

@smonkewitzいいえ、そのバヌゞョンでは、割り圓おステヌトメントにバむンドされおいるため、新しいキヌワヌドは必芁ありたせん。これは、これたでさたざたな構文糖衣構文で䜕床も蚀及されおきたした。

https://github.com/golang/go/issues/32437#issuecomment -499808741
https://github.com/golang/go/issues/32437#issuecomment -499852124
https://github.com/golang/go/issues/32437#issuecomment -500095505

@ianlancetaylorは、この特定の゚ラヌ凊理のフレヌバヌをgoチヌムによっおただ怜蚎されおいたすか 提案された組み蟌みの詊行ほど実装は簡単ではありたせんが、より慣甚的な感じがしたす。 〜䞍必芁な声明、ごめんなさい。〜

@deanveloperず他の数人が蚀ったこずを繰り返したいず思いたすが、私自身の匷調がありたす。 https://github.com/golang/go/issues/32437#issuecomment -498939499 @ deanveloperで次のように述べおいたす。

tryは条件付きの戻り倀です。 制埡フロヌずリタヌンはどちらもGoのペデスタルで保持されたす。 関数内のすべおの制埡フロヌはむンデントされ、すべおの戻り倀はreturnで始たりたす。 これらの抂念の䞡方を混ぜ合わせお、芋逃しやすい関数呌び出しにするず、少し気分が悪くなりたす。

さらに、この提案では、 tryは倀を返す関数であるため、より倧きな匏の䞀郚ずしお䜿甚できたす。

panicは、制埡フロヌを倉曎する組み蟌み関数の先䟋をすでに蚭定しおいるず䞻匵する人もいたすが、 panicは、次の2぀の理由で根本的に異なるず思いたす。

  1. パニックは条件付きではありたせん。 垞に呌び出し元の関数を䞭止したす。
  2. パニックは倀を返さないため、スタンドアロンステヌトメントずしおのみ衚瀺でき、可芖性が向䞊したす。

䞀方、詊しおみおください

  1. 条件付きです。 呌び出し元の関数から戻る堎合ず戻らない堎合がありたす。
  2. 倀を返し、耇合匏に、堎合によっおは耇数回、1行に衚瀺され、゚ディタヌりィンドりの右マヌゞンを超える可胜性がありたす。

これらの理由から、 tryは「少し離れた」感じではなく、コヌドの可読性を根本的に損なうず思いたす。

今日、初めおGoコヌドに遭遇したずき、それをすばやくスキミングしお、可胜な出口点ず制埡フロヌ点を芋぀けるこずができたす。 これはGoコヌドの非垞に䟡倀のあるプロパティだず思いたす。 tryを䜿甚するず、そのプロパティがないコヌドを曞くのが簡単になりすぎたす。

コヌドの可読性を重芖するGo開発者は、これらの可読性の萜ずし穎を回避するtryの䜿甚法のむディオムに収束する可胜性が高いこずを認めたす。 コヌドの可読性は倚くのGo開発者にずっおコアバリュヌであるように思われるので、そうなるこずを願っおいたす。 しかし、 tryが既存のコヌドむディオムに十分な䟡倀を远加しお、誰もが孊習できるように蚀語に新しい抂念を远加するずいう重みを持ち、それが読みやすさを損なう可胜性があるこずは私には明らかではありたせん。

`` ``
if it= "broke" {
dontFixit
}

@ChrisHines芁点このスレッドの他の堎所に゚コヌされたすに、別の制限を远加したしょう

  • tryステヌトメントハンドラヌがない堎合でもは、独自の行で発生する必芁がありたす。

それでも、芖芚的なノむズを倧幅に枛らすこずでメリットが埗られたす。 次に、 returnでアノテヌションが付けられたリタヌンず、 tryでアノテヌションが付けられた条件付きリタヌンが保蚌され、これらのキヌワヌドは垞に行の先頭たたは最悪の堎合、倉数の割り圓おの盎埌になりたす。

したがっお、このタむプのナンセンスはありたせん。

try EmitEvent(try (try DecodeMsg(m)).SaveToDB())

むしろこれ

dm := try DecodeMsg(m)
um := try dm.SaveToDB()
try EmitEvent(um)

これはただこれよりも明確に感じたす

dm, err := DecodeMsg(m)
if err != nil {
    return nil, err
}

um, err := dm.SaveToDB()
if err != nil {
    return nil, err
}

err = EmitEvent(um)
if err != nil {
    return nil, err
}

この蚭蚈で私が気に入っおいるこずの1぀は、゚ラヌが発生する可胜性があるこずを通知せずに、゚ラヌを黙っお無芖するこずは䞍可胜であるずいうこずです。 珟圚、 x, _ := SomeFunc() 無芖された戻り倀ずは䜕ですか゚ラヌ䜕か他のものですかが衚瀺されるこずがありたすが、明確に泚釈を付ける必芁がありたす。

x := try SomeFunc() else err {}

提案を支持する前回の投皿以来、 @ jagv パラメヌタヌなしのtryは*error $を返すず@josharian ラベル付き゚ラヌハンドラヌによっお投皿された2぀のアむデアを芋おきたした。わずかに倉曎されたフォヌムは、提案を倧幅に匷化したす。

これらのアむデアを私が持っおいた別のアむデアず組み合わせるず、 tryの4぀のバヌゞョンがありたす

  1. 詊す
  2. tryparams
  3. tryparams、label
  4. tryparams、panic

1は、゚ラヌ戻りパラメヌタヌERPぞのポむンタヌを返すか、パラメヌタヌがない堎合はnilを返したす4のみ。 これにより、さらにブルトむンを远加するこずなく、名前付きERPの代替手段が提䟛されたす。

2は、珟圚想定されおいるずおりに機胜したす。 nil以倖の゚ラヌはすぐに返されたすが、 deferステヌトメントで修食できたす。

3は、 @ josharianによっお提案されたように機胜したす。぀たり、nil以倖の゚ラヌでは、コヌドはラベルに分岐したす。 ただし、デフォルトの゚ラヌハンドララベルはありたせん。その堎合は2に瞮退するためです。

これは通垞、 deferよりも簡単で高速なので、゚ラヌを装食するたたはロヌカルで凊理しおからnilを返すためのより良い方法であるように思われたす。 それが気に入らなかった人は誰でも2を䜿うこずができたす。

゚ラヌ凊理ラベル/コヌドを関数の終わり近くに配眮し、関数本䜓の残りの郚分に戻らないようにするこずをお勧めしたす。 ただし、コンパむラが匷制する必芁はないず思いたす。これは、コンパむラが有甚である堎合があり、いずれの堎合も匷制が難しい堎合があるためです。

したがっお、通垞のラベルずgotoの動䜜は、 @ josharianが蚀ったようにサブゞェクトを最初に修正される26058に適甚したすが、ずにかく修正する必芁があるず思いたす。

ラベルの名前をpanicにするこずはできたせん。これは、4ず競合するためです。

4は、戻ったり分岐したりするのではなく、すぐにpanicになりたす。 したがっお、これが特定の関数で䜿甚されるtryの唯䞀のバヌゞョンである堎合、ERPは必芁ありたせん。

これを远加したので、テストパッケヌゞは、組み蟌みの倉曎やその他の倉曎を必芁ずせずに、珟圚ず同じように機胜したす。 ただし、他の_臎呜的な_シナリオでも圹立぀堎合がありたす。

これは、゚ラヌハンドラヌに分岐しおパニックに陥る代わりに、ERPが必芁になるため、 tryの別のバヌゞョンである必芁がありたす。

最初の提案に察する最も匷力なタむプの反応の1぀は、関数が戻る堎所の通垞のフロヌの容易な可芖性を倱うこずに関する懞念でした。

たずえば、 @ deanveloperは、 https //github.com/golang/go/issues/32437#issuecomment -498932961でその懞念を非垞によく衚珟したした。これは、ここで最も賛成されたコメントだず思いたす。

@dominikhはhttps://github.com/golang/go/issues/32437#issuecomment-499067357に曞き蟌みたした

gofmtされたコヌドでは、returnは垞に/ ^ \ t * return /ず䞀臎したす。これは、支揎なしで目で確認するのは非垞に簡単なパタヌンです。 䞀方、tryはコヌド内のどこでも発生する可胜性があり、関数呌び出しの奥深くに任意にネストされたす。 どんなに倚くのトレヌニングを行っおも、ツヌルの支揎なしに、関数内のすべおの制埡フロヌをすぐに芋぀けるこずができたす。

それを助けるために、 @ brynbellomyは昚日提案したした

すべおのtryステヌトメントハンドラヌがない堎合でもは、独自の行で発生する必芁がありたす。

さらに蚀えば、割り圓おの堎合でも、 tryが行の先頭である必芁がありたす。

したがっお、次のようになりたす。

try dm := DecodeMsg(m)
try um := dm.SaveToDB()
try EmitEvent(um)

以䞋ではなく @brynbellomyの䟋から

dm, err := DecodeMsg(m)
if err != nil {
    return nil, err
}

um, err := dm.SaveToDB()
if err != nil {
    return nil, err
}

err = EmitEvent(um)
if err != nil {
    return nil, err
}

それは、線集者やIDEの支揎がなくおも、ボむラヌプレヌトを枛らしながら、かなりの量の可芖性を維持するようです。

これは、名前付き結果パラメヌタヌに䟝存する珟圚提案されおいる延期ベヌスのアプロヌチで機胜するか、通垞のハンドラヌ関数を指定しお機胜する可胜性がありたす。 名前付きの戻り倀を必芁ずせずにハンドラヌ関数を指定するこずは、名前付きの戻り倀を必芁ずするよりも私には良いように思えたすが、それは別のポむントです。

提案には次の䟋が含たれおいたす。

info := try(try(os.Open(file)).Stat())    // proposed try built-in

代わりに次のようになりたす。

try f := os.Open(file)
try info := f.Stat()

それは、提案された構文ほど短くはないにしおも、今日誰かが曞くかもしれないものず比范しお、ボむラヌプレヌトの削枛です。 おそらくそれは十分に短いでしょう

@ elagergren-spideroakはこの䟋を提䟛したした

try(try(try(to()).parse().this)).easily())

私はそれがミスマッチなparensを持っおいるず思いたす、それはおそらく意図的なポむントたたは埮劙なナヌモアのビットです、それでその䟋が2 tryたたは3 tryを持぀こずを意図しおいるかどうかはわかりたせん。 いずれにせよ、おそらくtryで始たる2〜3行に分散する必芁があるでしょう。

@thepudds 、これは私が以前のコメントで埗おいたものです。 䞎えられたものを陀いお

try f := os.Open(file)
try info := f.Stat()

明らかなこずは、 tryを、耇数の文を括匧で囲むこずができるtryブロックず考えるこずです。 したがっお、䞊蚘は

try (
    f := os.Open(file)
    into := f.Stat()
)

コンパむラがこれに察凊する方法を知っおいる堎合、同じこずがネストにも機胜したす。 だから今、䞊蚘は

try info := os.Open(file).Stat()

関数のシグネチャから、コンパむラはOpenが゚ラヌ倀を返す可胜性があるこずを認識しおおり、tryブロックにあるため、゚ラヌ凊理を生成しおから、プラむマリ戻り倀に察しおStatを呌び出す必芁がありたす。

次に、゚ラヌ倀が生成されおいないか、ロヌカルで凊理されるステヌトメントを蚱可したす。 だからあなたは今蚀うこずができたす

try (
    f := os.Open(file)
    debug("f: %v\n", f) // debug returns nothing
    into := f.Stat()
)

これにより、tryブロックを再配眮せずにコヌドを進化させるこずができたす。 しかし、いく぀かの奇劙な理由で、゚ラヌ凊理は明瀺的に説明する必芁があるず人々は考えおいるようです。 圌らは欲しい

try(try(try(to()).parse()).this)).easily())

私は完党に元気ですが

try to().parse().this().easily()

どちらの堎合でも、たったく同じ゚ラヌチェックコヌドを生成できたす。 私の芋解では、必芁に応じおい぀でも゚ラヌ凊理甚の特別なコヌドを曞くこずができたす。 try たたは任意の呌び出し方は、デフォルトの゚ラヌ凊理呌び出し元にパントするこずを単玔に敎理したす。

もう1぀の利点は、コンパむラヌがデフォルトの゚ラヌ凊理を生成する堎合、䞊蚘の4぀の機胜のどれが倱敗したかを知るこずができるように、さらに識別情報を远加できるこずです。

tryが他の匏の䞭に珟れるプログラムの読みやすさに぀いお少し心配したした。 そこで、暙準ラむブラリでgrep "return .*err$"を実行し、ブロックをランダムに読み始めたした。 7214件の結果がありたすが、私は数癟件しか読んでいたせん。

最初に泚意すべきこずは、 tryが適甚される堎合、これらのブロックのほずんどすべおがもう少し読みやすくなるこずです。

2぀目は、これらのうち10分の1未満のごく少数が、別の匏の䞭にtryを入れるこずです。 兞型的なケヌスは、 x := try(...)たたは^try(...)$の圢匏のステヌトメントです。

tryが別の匏の䞭に衚瀺されるいく぀かの䟋を次に瀺したす。

テキスト/テン​​プレヌト

func gt(arg1, arg2 reflect.Value) (bool, error) {
        // > is the inverse of <=.
        lessOrEqual, err := le(arg1, arg2)
        if err != nil {
                return false, err
        }
        return !lessOrEqual, nil
}

になりたす

func gt(arg1, arg2 reflect.Value) (bool, error) {
        // > is the inverse of <=.
        return !try(le(arg1, arg2)), nil
}

テキスト/テン​​プレヌト

func index(item reflect.Value, indices ...reflect.Value) (reflect.Value, error) {
...
        switch v.Kind() {
        case reflect.Map:
                index, err := prepareArg(index, v.Type().Key())
                if err != nil {
                        return reflect.Value{}, err
                }
                if x := v.MapIndex(index); x.IsValid() {
                        v = x
                } else {
                        v = reflect.Zero(v.Type().Elem())
                }
        ...
        }
}

になりたす

func index(item reflect.Value, indices ...reflect.Value) (reflect.Value, error) {
        ...
        switch v.Kind() {
        case reflect.Map:
                if x := v.MapIndex(try(prepareArg(index, v.Type().Key()))); x.IsValid() {
                        v = x
                } else {
                        v = reflect.Zero(v.Type().Elem())
                }
        ...
        }
}

これは私が芋た䞭で最も疑わしい䟋です

正芏衚珟/構文

regexp/syntax/parse.go

func Parse(s string, flags Flags) (*Regexp, error) {
        ...
        if c, t, err = nextRune(t); err != nil {
                return nil, err
        }
        p.literal(c)
        ...
}

になりたす

func Parse(s string, flags Flags) (*Regexp, error) {
        ...
        c, t = try(nextRune(t))
        p.literal(c)
        ...
}

これは別の匏の䞭で詊しおみる䟋ではありたせんが、読みやすさを向䞊させるために呌び出したいず思いたす。 ここで、 cずtの倀がifステヌトメントの範囲を超えお存圚しおいるこずを確認するのははるかに簡単です。

ネット/ http

net / http / request.goreadRequest

        mimeHeader, err := tp.ReadMIMEHeader()
        if err != nil {
                return nil, err
        }
        req.Header = Header(mimeHeader)

になりたす

        req.Header = Header(try(tp.ReadMIMEHeader())

デヌタベヌス/ SQL

        if driverCtx, ok := driveri.(driver.DriverContext); ok {
                connector, err := driverCtx.OpenConnector(dataSourceName)
                if err != nil {
                        return nil, err
                }
                return OpenDB(connector), nil
        }

になりたす

        if driverCtx, ok := driveri.(driver.DriverContext); ok {
                return OpenDB(try(driverCtx.OpenConnector(dataSourceName))), nil
        }

デヌタベヌス/ SQL

        si, err := ctxDriverPrepare(ctx, dc.ci, query)
        if err != nil {
                return nil, err
        }
        ds := &driverStmt{Locker: dc, si: si}

になりたす

        ds := &driverStmt{
                Locker: dc,
                si: try(ctxDriverPrepare(ctx, dc.ci, query)),
        }

ネット/ http

        if http2isconnectioncloserequest(req) && dialonmiss {
                // it gets its own connection.
                http2tracegetconn(req, addr)
                const singleuse = true
                cc, err := p.t.dialclientconn(addr, singleuse)
                if err != nil {
                        return nil, err
                }
                return cc, nil
        }

になりたす

        if http2isconnectioncloserequest(req) && dialonmiss {
                // it gets its own connection.
                http2tracegetconn(req, addr)
                const singleuse = true
                return try(p.t.dialclientconn(addr, singleuse))
        }

ネット/ http

func (f *http2Framer) endWrite() error {
        ...
        n, err := f.w.Write(f.wbuf)
        if err == nil && n != len(f.wbuf) {
                err = io.ErrShortWrite
        }
        return err
}

になりたす

func (f *http2Framer) endWrite() error {
        ...
        if try(f.w.Write(f.wbuf) != len(f.wbuf) {
                return io.ErrShortWrite
        }
        return nil
}

これは私が本圓に奜きです。

ネット/ http

        if f, err := fr.ReadFrame(); err != nil {
                return nil, err
        } else {
                hc = f.(*http2ContinuationFrame) // guaranteed by checkFrameOrder
        }

になりたす

        hc = try(fr.ReadFrame()).(*http2ContinuationFrame)// guaranteed by checkFrameOrder

}

たたいいです。

ネット

        if ctrlFn != nil {
                c, err := newRawConn(fd)
                if err != nil {
                        return err
                }
                if err := ctrlFn(fd.ctrlNetwork(), laddr.String(), c); err != nil {
                        return err
                }
        }

になりたす

        if ctrlFn != nil {
                try(ctrlFn(fd.ctrlNetwork(), laddr.String(), try(newRawConn(fd))))
        }

倚分これは倚すぎたす、そしお代わりにそれはそうあるべきです

        if ctrlFn != nil {
                c := try(newRawConn(fd))
                try(ctrlFn(fd.ctrlNetwork(), laddr.String(), c))
        }

党䜓ずしお、私が読んだ暙準ラむブラリコヌドに察するtryの効果を非垞に楜しんでいたす。

最埌のポむント提案のいく぀かの䟋を超えおコヌドを読むためにtryが適甚されるのを芋るのは、啓発的でした。 tryを䜿甚するようにコヌドを自動的に倉換するツヌルを䜜成するこずを怜蚎する䟡倀があるず思いたすプログラムのセマンティクスは倉曎されたせん。 githubで人気のあるパッケヌゞに察しお生成されたdiffのサンプルを読んで、暙準ラむブラリで芋぀けたものが維持されるかどうかを確認するのは興味深いこずです。 このようなプログラムの出力は、提案の効果に぀いおの远加の掞察を提䟛する可胜性がありたす。

@crawshawこれをしおくれおありがずう、それが実際に動いおいるのを芋るのは玠晎らしかった。 しかし、それが実際に動䜜しおいるのを芋るず、これたで华䞋しおいたむンラむン゚ラヌ凊理に察する議論をより真剣に受け止めるこずができたした。

これは、 tryをステヌトメントにするずいう@thepuddsの興味深い提案に非垞に近いため、その構文を䜿甚しおすべおの䟋を曞き盎し、匏tryたたは珟状維持、䜙分な行をあたり必芁ずしない

func gt(arg1, arg2 reflect.Value) (bool, error) {
        // > is the inverse of <=.
        try lessOrEqual := le(arg1, arg2)
        return !lessOrEqual, nil
}
func index(item reflect.Value, indices ...reflect.Value) (reflect.Value, error) {
        ...
        switch v.Kind() {
        case reflect.Map:
                try index := prepareArg(index, v.Type().Key())
                if x := v.MapIndex(index); x.IsValid() {
                        v = x
                } else {
                        v = reflect.Zero(v.Type().Elem())
                }
        ...
        }
}
func Parse(s string, flags Flags) (*Regexp, error) {
        ...
        try c, t = nextRune(t)
        p.literal(c)
        ...
}
        try mimeHeader := tp.ReadMIMEHeader()
        req.Header = Header(mimeHeader)
        if driverCtx, ok := driveri.(driver.DriverContext); ok {
                try connector := driverCtx.OpenConnector(dataSourceName)
                return OpenDB(connector), nil
        }

これは、匏を䜿甚した方が間違いなく優れおいたすtry線集する必芁のあるフィヌルドが耇数ある堎合は、 tryですが、それでもこのトレヌドオフのバランスを優先したす

        try si := ctxDriverPrepare(ctx, dc.ci, query)
        ds := &driverStmt{Locker: dc, si: si}

これは基本的にこれの最悪のケヌスであり、問​​題ないように芋えたす。

        if http2isconnectioncloserequest(req) && dialonmiss {
                // it gets its own connection.
                http2tracegetconn(req, addr)
                const singleuse = true
                try cc := p.t.dialclientconn(addr, singleuse)
                return cc, nil
        }

私はif tryが合法であるか合法であるかに぀いお自分自身で議論したしたが、なぜ合法である必芁がないのかに぀いお合理的な説明を思い付くこずができず、ここで非垞にうたく機胜したす。

func (f *http2Framer) endWrite() error {
        ...
        if try n := f.w.Write(f.wbuf); n != len(f.wbuf) {
                return io.ErrShortWrite
        }
        return nil
}
        try f := fr.ReadFrame()
        hc = f.(*http2ContinuationFrame) // guaranteed by checkFrameOrder
        if ctrlFn != nil {
                try c := newRawConn(fd)
                try ctrlFn(fd.ctrlNetwork(), laddr.String(), c)
        }

@crawshawの䟋をスキャンするず、制埡フロヌが蚭蚈にさらに泚意を払うのに十分なほど暗号化されおいないこずがよくあるず確信できたす。 少しでも耇雑さを関連付けるず、読みにくくなり、倱敗しやすくなりたす。 オプションが怜蚎されおいるのを芋おうれしいですが、そのような保護された蚀語での制埡フロヌを耇雑にするこずは、非垞に性栌が悪いようです。

func (f *http2Framer) endWrite() error {
        ...
        if try(f.w.Write(f.wbuf) != len(f.wbuf) {
                return io.ErrShortWrite
        }
        return nil
}

たた、 tryは䜕も「詊行」しおいたせん。 それは「保護リレヌ」です。 提案の基本セマンティクスがオフの堎合、結果のコヌドにも問題があるのは驚きではありたせん。

func (f *http2Framer) endWrite() error {
        ...
        relay n := f.w.Write(f.wbuf)
        return checkShortWrite(n, len(f.wbuf))
}

ステヌトメントを詊しおみる堎合は、フラグを䜿甚しお、どの戻り倀ずどのアクションを瀺すこずができたす。

try c, @      := newRawConn(fd) // return
try c, <strong i="6">@panic</strong> := newRawConn(fd) // panic
try c, <strong i="7">@hname</strong> := newRawConn(fd) // invoke named handler
try c, <strong i="8">@_</strong>     := newRawConn(fd) // ignore, or invoke "ignored" handler if defined

少なくずもパニックず無芖アクションには、サブ匏構文が必芁ですRussはそれが芁件であるず述べおいたす。

たず、 @ crawshawが、玄200の実際の䟋を芋お、䞊蚘の圌の思慮深い蚘事に時間を割いおくれたこずに拍手を送りたす。

次に、 @ jimmyfrasche 、 http2Framerの䟋に関するここでの回答に぀いお


私はif tryが合法であるか合法であるかに぀いお自分自身で議論したしたが、なぜ合法である必芁がないのかに぀いお合理的な説明を思い付くこずができず、ここで非垞にうたく機胜したす。

`` `
funcf * http2FramerendWrite゚ラヌ{
..。
nを詊しおみる堎合= fwWritef.wbuf; n= lenf.wbuf{
io.ErrShortWriteを返したす
}
nilを返す
}

At least under what I was suggesting above in https://github.com/golang/go/issues/32437#issuecomment-500213884, under that proposal variation I would suggest `if try` is not allowed.

That `http2Framer` example could instead be:

funcf * http2FramerendWrite゚ラヌ{
..。
nを詊しおください= fwWritef.wbuf
n= lenf.wbuf{の堎合
io.ErrShortWriteを返したす
}
nilを返す
}
`` That is one line longer, but hopefully still "light on the page". Personally, I think that (arguably) reads more cleanly, but more importantly it is easier to see the try`。

@deanveloperは䞊蚘のhttps://github.com/golang/go/issues/32437#issuecomment-49892961に曞き蟌みたした。

関数から戻るこずは「神聖な」こずだったようです

その特定のhttp2Framerの䟋は、最終的には可胜な限り短くはなりたせん。 ただし、 tryが行の最初のものでなければならない堎合は、関数からの埩垰をより「神聖な」ものにしたす。

@crawshawは蚀及したした

2぀目は、これらのうち10分の1未満のごく少数が、別の匏の䞭に詊しおみるずいうこずです。 兞型的なケヌスは、x= try...たたは^ try...$の圢匏のステヌトメントです。

特に、$ try tryが行の最初のものである必芁がありたすか

@jimmyfrasche

@crawshawこれをしおくれおありがずう、それが実際に動いおいるのを芋るのは玠晎らしかった。 しかし、それが実際に動䜜しおいるのを芋るず、これたで华䞋しおいたむンラむン゚ラヌ凊理に察する議論をより真剣に受け止めるこずができたした。

これは、 tryをステヌトメントにするずいう@thepuddsの興味深い提案に非垞に近いため、その構文を䜿甚しおすべおの䟋を曞き盎し、匏tryたたは珟状維持、䜙分な行をあたり必芁ずしない

func gt(arg1, arg2 reflect.Value) (bool, error) {
        // > is the inverse of <=.
        try lessOrEqual := le(arg1, arg2)
        return !lessOrEqual, nil
}

最初の䟋は、私が匏tryを匷く奜む理由をよく瀺しおいたす。 あなたのバヌゞョンでは、 leの呌び出しの結果を倉数に入れる必芁がありたすが、その倉数には、 leずいう甚語がただ意味しおいないずいう意味はありたせん。 したがっお、意味がない xのようにたたは冗長な lessOrEqualのように名前を付けるこずはできたせん。 匏tryを䜿甚するず、䞭間倉数は必芁ないため、この問題は発生したせん。

匿名のたたにしおおくほうがよい名前を発明するために、粟神的な努力を費やす必芁はありたせん。

try キヌワヌドが行の先頭に移動された最埌のいく぀かの投皿の背埌でサポヌトを提䟛できるこずをうれしく思いたす。 returnず同じ芖芚空間を共有する必芁がありたす。

Re @jimmyfrascheが耇合ifステヌトメント内でtryを蚱可するずいう提案は、いく぀かの理由から、ここで倚くの人が避けようずしおいるこずずたったく同じです。

  • 2぀の非垞に異なる制埡フロヌメカニズムを1぀のラむンに統合したす
  • try匏が実際に最初に評䟡され、関数が返される可胜性がありたすが、 ifの埌に衚瀺されたす。
  • それらはたったく異なる゚ラヌで返されたす。そのうちの1぀は実際にはコヌドに衚瀺されたせんが、もう1぀はコヌドに衚瀺されたす。
  • ブロックはハンドラヌブロックによく䌌おいるため、 tryが実際に凊理されおいないこずがわかりにくくなりたすたったく異なる問題を凊理しおいる堎合でも

tryを凊理するように人々を促すこずを奜む、わずかに異なる角床からこの状況にアプロヌチするこずができたす。 try / else構文に埌続の条件を含めるこずを蚱可するのはどうですかこれは、 errずnの䞡方を返す倚くのI / O関数で䞀般的なパタヌンです。

func (f *http2Framer) endWrite() error {
        // ...
        try n := f.w.Write(f.wbuf) else err {
                return errors.Wrap(err, "error writing:")
        } else if n != len(f.wbuf) {
                return io.ErrShortWrite
        }
        return nil
}

.Writeによっお返された゚ラヌを凊理しない堎合でも、 .Writeが゚ラヌになる可胜性があるずいう明確な泚釈がありたす@thepuddsが指摘しおいるように。

func (f *http2Framer) endWrite() error {
        // ...
        try n := f.w.Write(f.wbuf)
        if n != len(f.wbuf) {
                return io.ErrShortWrite
        }
        return nil
}

2番目の@davedの応答。 私の意芋では、 @ crawshawが匷調衚瀺した各䟋は、 tryの結果ずしお、明確でなくなり、゚ラヌが発生しやすくなりたした。

try キヌワヌドが行の先頭に移動された最埌のいく぀かの投皿の背埌でサポヌトを提䟛できるこずをうれしく思いたす。 returnず同じ芖芚空間を共有する必芁がありたす。

この点で2぀のオプションがあり、1぀が遞択され、将来の朜圚的な機胜の前䟋ずなるず仮定するず、次のようになりたす。

A.

try f := os.Open(filepath) else err {
    return errors.Wrap(err, "can't open")
}

B.

f := try os.Open(filepath) else err {
    return errors.Wrap(err, "can't open")
}

2぀のうちどちらが、将来の新しいキヌワヌドの䜿甚に察しおより柔軟性を提䟛したすか _私はコンパむラヌを曞くずいうダヌクアヌトをマスタヌしおいないので、これに察する答えはわかりたせん。_あるアプロヌチは別のアプロヌチよりも制限がありたすか

@davecheney @daved @crawshaw
私はこれに぀いおDavesに同意する傟向がありたす。 @ crawshawの䟋では、他の倚くのこずが行われおいる行の奥深くに埋め蟌たれたtryステヌトメントがたくさんありたす。 出口点を芋぀けるのは本圓に難しい。 さらに、いく぀かの䟋では、 tryのパレンがかなりひどく乱雑になっおいるようです。

このように倉換された䞀連のstdlibコヌドを芋るず非垞に䟿利なので、同じ䟋を取り䞊げたしたが、より制限の厳しい代替案に埓っお曞き盎したした。

  • キヌワヌドずしおtry
  • 1行に1぀だけtry
  • tryは行の先頭にある必芁がありたす

うたくいけば、これは私たちが比范するのに圹立぀でしょう。 個人的には、これらの䟋は元の䟋よりもはるかに簡朔に芋えたすが、制埡フロヌを曖昧にするこずはありたせん。 tryは、䜿甚されおいる堎所ならどこでも非垞に目立ちたす。

テキスト/テン​​プレヌト

func gt(arg1, arg2 reflect.Value) (bool, error) {
        // > is the inverse of <=.
        lessOrEqual, err := le(arg1, arg2)
        if err != nil {
                return false, err
        }
        return !lessOrEqual, nil
}

になりたす

func gt(arg1, arg2 reflect.Value) (bool, error) {
        // > is the inverse of <=.
        try lessOrEqual := le(arg1, arg2)
        return !lessOrEqual, nil
}

テキスト/テン​​プレヌト

func index(item reflect.Value, indices ...reflect.Value) (reflect.Value, error) {
...
        switch v.Kind() {
        case reflect.Map:
                index, err := prepareArg(index, v.Type().Key())
                if err != nil {
                        return reflect.Value{}, err
                }
                if x := v.MapIndex(index); x.IsValid() {
                        v = x
                } else {
                        v = reflect.Zero(v.Type().Elem())
                }
        ...
        }
}

になりたす

func index(item reflect.Value, indices ...reflect.Value) (reflect.Value, error) {
        ...
        switch v.Kind() {
        case reflect.Map:
                try index := prepareArg(index, v.Type().Key())
                if x := v.MapIndex(index); x.IsValid() {
                        v = x
                } else {
                        v = reflect.Zero(v.Type().Elem())
                }
        ...
        }
}

正芏衚珟/構文

regexp/syntax/parse.go

func Parse(s string, flags Flags) (*Regexp, error) {
        ...
        if c, t, err = nextRune(t); err != nil {
                return nil, err
        }
        p.literal(c)
        ...
}

になりたす

func Parse(s string, flags Flags) (*Regexp, error) {
        ...
        try c, t = nextRune(t)
        p.literal(c)
        ...
}

ネット/ http

net / http / request.goreadRequest

        mimeHeader, err := tp.ReadMIMEHeader()
        if err != nil {
                return nil, err
        }
        req.Header = Header(mimeHeader)

になりたす

        try mimeHeader := tp.ReadMIMEHeader()
        req.Header = Header(mimeHeader)

デヌタベヌス/ SQL

        if driverCtx, ok := driveri.(driver.DriverContext); ok {
                connector, err := driverCtx.OpenConnector(dataSourceName)
                if err != nil {
                        return nil, err
                }
                return OpenDB(connector), nil
        }

になりたす

        if driverCtx, ok := driveri.(driver.DriverContext); ok {
                try connector := driverCtx.OpenConnector(dataSourceName)
                return OpenDB(connector), nil
        }

デヌタベヌス/ SQL

        si, err := ctxDriverPrepare(ctx, dc.ci, query)
        if err != nil {
                return nil, err
        }
        ds := &driverStmt{Locker: dc, si: si}

になりたす

        try si := ctxDriverPrepare(ctx, dc.ci, query)
        ds := &driverStmt{Locker: dc, si: si}

ネット/ http

        if http2isconnectioncloserequest(req) && dialonmiss {
                // it gets its own connection.
                http2tracegetconn(req, addr)
                const singleuse = true
                cc, err := p.t.dialclientconn(addr, singleuse)
                if err != nil {
                        return nil, err
                }
                return cc, nil
        }

になりたす

        if http2isconnectioncloserequest(req) && dialonmiss {
                // it gets its own connection.
                http2tracegetconn(req, addr)
                const singleuse = true
                try cc := p.t.dialclientconn(addr, singleuse)
                return cc, nil
        }

ネット/ http
これは実際には行を節玄したせんが、 if err == nilは比范的珍しい構造であるため、はるかに明確です。

func (f *http2Framer) endWrite() error {
        ...
        n, err := f.w.Write(f.wbuf)
        if err == nil && n != len(f.wbuf) {
                err = io.ErrShortWrite
        }
        return err
}

になりたす

func (f *http2Framer) endWrite() error {
        ...
        try n := f.w.Write(f.wbuf)
        if n != len(f.wbuf) {
                return io.ErrShortWrite
        }
        return nil
}

ネット/ http

        if f, err := fr.ReadFrame(); err != nil {
                return nil, err
        } else {
                hc = f.(*http2ContinuationFrame) // guaranteed by checkFrameOrder
        }

になりたす

        try f := fr.ReadFrame()
        hc = f.(*http2ContinuationFrame) // guaranteed by checkFrameOrder
}

ネット

        if ctrlFn != nil {
                c, err := newRawConn(fd)
                if err != nil {
                        return err
                }
                if err := ctrlFn(fd.ctrlNetwork(), laddr.String(), c); err != nil {
                        return err
                }
        }

になりたす

        if ctrlFn != nil {
                try c := newRawConn(fd)
                try ctrlFn(fd.ctrlNetwork(), laddr.String(), c)
        }

@ james-lawrence https://github.com/golang/go/issues/32437#issuecomment -500116099ぞの返信オプションの, errが真剣に怜蚎されおいるようなアむデアは思い出せたせん。 個人的には悪い考えだず思いたす。関数が倉曎されお末尟のerrorパラメヌタヌが远加された堎合、既存のコヌドはコンパむルを続行したすが、動䜜が倧きく異なるためです。

゚ラヌの凊理にdeferを䜿甚するこずは非垞に理にかなっおいたすが、゚ラヌに名前を付ける必芁があり、新しい皮類のif err != nilボむラヌプレヌトが必芁になりたす。

倖郚ハンドラヌはこれを行う必芁がありたす

func handler(err *error) {
  if *err != nil {
    *err = handle(*err)
  }
} 

のように䜿甚されたす

defer handler(&err)

倖郚ハンドラヌを䜜成する必芁があるのは1回だけですが、倚くの゚ラヌ凊理関数には2぀のバヌゞョンが必芁です。1぀は延期するためのもので、もう1぀は通垞の方法で䜿甚するためのものです。

内郚ハンドラヌはこれを行う必芁がありたす

defer func() {
  if err != nil {
    err = handle(err)
  }
}()

どちらの堎合も、アクセスするには、倖郚関数の゚ラヌに名前を付ける必芁がありたす。

スレッドで前述したように、これは単䞀の関数に抜象化できたす。

func catch(err *error, handle func(error) error) {
  if *err != nil && handle != nil {
    *err = handle(*err)
  }
}

これは、 nilハンドラヌ関数のあいたいさに察する@griesemerの懞念に反するものであり、 errに名前を付ける必芁があるこずに加えお、独自のdeferずfunc(err error) errorの定型文がありたす。倖偎の関数のerr 。

tryがキヌワヌドずしお䜿甚される堎合は、以䞋で説明するように、 catchキヌワヌドを䜿甚するこずも意味がありたす。

構文的には、 handleのようになりたす。

catch err {
  return handleThe(err)
}

意味的には、䞊蚘の内郚ハンドラヌコヌドの砂糖になりたす。

defer func() {
  if err != nil {
    err = handleThe(err)
  }
}()

やや䞍思議なため、名前が付けられおいなくおも、倖郚関数の゚ラヌを取埗する可胜性がありたす。  catch $の埌の$ err $は、 catchブロックのパラメヌタヌ名に䌌おいたす。

catchには、 tryず同じ制限があり、どちらもそれに䟝存する砂糖であるため、最終的な゚ラヌが返される関数内にある必芁がありたす。

これは、元のhandleの提案ほど匷力ではありたせんが、゚ラヌを凊理するために゚ラヌに名前を付ける必芁がなくなり、内郚ハンドラヌに぀いお䞊蚘で説明した新しいボむラヌプレヌトが削陀されたす。倖郚ハンドラヌ甚に個別のバヌゞョンの関数が必芁です。

耇雑な゚ラヌ凊理では、 tryを䜿甚しない堎合ず同じように、 catchを䜿甚しない必芁がある堎合がありたす。

これらは䞡方ずも砂糖なので、 catchをtry $ず䞀緒に䜿甚する必芁はありたせん。 catchハンドラヌは、関数がnil以倖の゚ラヌを返すたびに実行されたす。これにより、たずえば、いく぀かのクむックログを保持できたす。

catch err {
  log.Print(err)
  return err
}

たたは、返されたすべおの゚ラヌをラップするだけです。

catch err {
  return fmt.Errorf("foo: %w", err)
}

@ianlancetaylor

_ "関数が倉曎されお末尟のerrorパラメヌタが远加された堎合、既存のコヌドはコンパむルを続行したすが、動䜜が倧きく異なるため、これは悪い考えだず思いたす。" _

これはおそらく正しい芋方です。アップストリヌムコヌドずダりンストリヌムコヌドの䞡方を制埡できる堎合は、゚ラヌを返すために関数シグネチャを倉曎する必芁がある堎合は、そうするこずができたす。

しかし、誰かが自分のパッケヌゞのアップストリヌムたたはダりンストリヌムを制埡しない堎合はどうなるかを怜蚎しおください。 たた、゚ラヌが远加される可胜性のあるナヌスケヌスを怜蚎し、゚ラヌを远加する必芁があるが、ダりンストリヌムコヌドを匷制的に倉曎できない堎合はどうなりたすか

誰かが眲名を倉曎しお戻り倀を远加する䟋を考えおみおください。 私にずっお、圌らは通垞、_「゚ラヌが発生するこずに気づかなかった」_たたは_「゚ラヌが発生しない可胜性があるため、怠惰に感じお努力したくない」ずいうカテゎリに分類されたす。 _

どちらの堎合も、゚ラヌを凊理する必芁があるこずが明らかになるため、゚ラヌリタヌンを远加する堎合がありたす。 その堎合、自分のパッケヌゞを䜿甚しおいる他の開発者ずの互換性を壊したくないために眲名を倉曎できない堎合はどうすればよいですか 私の掚枬では、゚ラヌが発生する時間の倧郚分ず、゚ラヌを返さないfuncを呌び出したコヌドは、非垞に異なる動䜜をしたす。

実際、私は埌者をめったに行いたせんが、前者を頻繁に行いたす。 しかし、サヌドパヌティのパッケヌゞは、あるべき堎所での゚ラヌのキャプチャを無芖するこずがよくありたす。これは、GoLandフラグでコヌドを衚瀺するず、すべおのむンスタンスが明るいオレンゞ色になるためです。 よく䜿甚するパッケヌゞに゚ラヌ凊理を远加するためにプルリク゚ストを送信できるようにしたいず思いたすが、コヌドの眲名が壊れおしたうため、ほずんどの堎合は受け入れたせん。

関数によっお返される゚ラヌを远加する䞋䜍互換性のある方法を提䟛しないこずにより、コヌドを配垃し、ナヌザヌのために物事を壊さないように気を配る開発者は、必芁に応じお゚ラヌ凊理を含めるようにパッケヌゞを進化させるこずができなくなりたす。


たぶん、コヌドが異なる動䜜をするずいう問題を考えるのではなく、゚ラヌを積極的にキャプチャしおいないメ゜ッドの欠点を最小限に抑える方法に関する゚ンゞニアリング䞊の課題ずしお問題を芋るのではないでしょうか。 それはより広く、より長期的な䟡倀を持぀でしょう。

たずえば、゚ラヌを無芖できるようになる前に蚭定する必芁があるパッケヌゞ゚ラヌハンドラヌを远加するこずを怜蚎しおください。


率盎に蚀っお、通垞の戻り倀に加えお゚ラヌを返すずいうGoのむディオムは、その優れた革新の1぀でした。 しかし、物事を改善するずきによくあるこずですが、他の匱点を明らかにするこずがよくありたす。Goの゚ラヌ凊理は十分に革新しおいなかったず私は䞻匵したす。

私たちGophersは䟋倖をスロヌするのではなく゚ラヌを返すこずに没頭しおいるので、私が持っおいる質問は_「なぜすべおの関数から゚ラヌを返すべきではないのですか」それを䜿っおコヌディングするよりも䟿利です。 したがっお、゚ラヌ凊理から逃れるこずができるず考える堎合は、゚ラヌ凊理を省略したす。 しかし、私たちはしばしば間違っおいるず思いたす。

したがっお、実際には、コヌドを゚レガントで読みやすくする方法を理解できれば、戻り倀ず゚ラヌは実際には別々に凊理する必芁があり、 _every_関数には過去の関数シグネチャに関係なく゚ラヌを返す機胜が必芁であるず䞻匵したす。 たた、既存のコヌドで゚ラヌを生成するコヌドを適切に凊理できるようにするこずは、䟡倀のある取り組みです。

実行可胜な構文を想像できなかったため、䜕も提案しおいたせんが、正盎に蚀うず、このスレッドのすべおがGoの゚ラヌ凊理に関連しおいるわけではなく、゚ラヌ凊理ずプログラムロゞックは奇劙な仲間なので、理想的にぱラヌは䜕らかの方法で垯域倖で凊理するのが最善でしょうか

キヌワヌドずしおのtryは、確かに読みやすさ関数呌び出しず比范しおに圹立ち、それほど耇雑ではないようです。 @brynbellomy @crawshaw䟋を曞くために時間を割いおいただき、ありがずうございたす。

私の䞀般的な考えは、 tryはやりすぎだず思いたす。 それは解決したす関数を呌び出し、倉数を割り圓お、゚ラヌをチェックし、存圚する堎合ぱラヌを返したす。 代わりにスコヌプを切り取り、条件付きの戻り倀のみを解決するこずを提案したす「最埌の匕数がnilでない堎合は戻り倀」。

これはおそらく新しいアむデアではありたせん...しかし、゚ラヌフィヌドバックりィキで提案をざっず読んだ埌、私はそれを芋぀けられたせんでしたそれがそこにないずいう意味ではありたせん

条件付きリタヌンに関するミニ提案

抜粋

err, thing := newThing(name)
refuse nil, err

りィキにも「代替案」の䞋に远加したした

䜕もしないこずも非垞に合理的な遞択肢のようです。

@alexhornbakeは、少し違うアむデアを私に䞎えおくれたす。

assert(nil, err)
assert(len(a), len(b))
assert(true, condition)
assert(expected, given)

このように、゚ラヌチェックだけでなく、倚くの皮類の論理゚ラヌにも適甚されたす。

指定されたものぱラヌにラップされお返されたす。

@alexhornbake

tryが実際に詊行しおいないように、 refuseは実際には「拒吊」しおいたせん。 ここでの䞀般的な目的は、有線の倀の1぀が条件を満たしたずきに「トリップ」する「保護リレヌ」 relayは短く、正確で、 returnに頭韻法を蚭定するこずです。 ぀たり、nil以倖の゚ラヌです。 これは䞀皮のサヌキットブレヌカヌであり、蚭蚈が面癜くないケヌスに限定されおいお、最もぶら䞋がっおいるボむラヌプレヌトの䞀郚を単玔に枛らすこずができれば、付加䟡倀が埗られるず思いたす。 リモヌトで耇雑なものはすべお、プレヌンなGoコヌドに䟝存する必芁がありたす。

たた、cranshawが暙準ラむブラリを調べお䜜業したこずを称賛したすが、結論は倧きく異なりたす...これらのコヌドスニペットのほずんどすべおが読みにくくなり、誀解されやすくなるず思いたす。

        req.Header = Header(try(tp.ReadMIMEHeader())

これが゚ラヌになる可胜性があるこずを私はしばしば芋逃したす。 簡単に読むず、「わかりたした。ヘッダヌをReadMimeHeaderのヘッダヌに蚭定しおください」ず衚瀺されたす。

        if driverCtx, ok := driveri.(driver.DriverContext); ok {
                return OpenDB(try(driverCtx.OpenConnector(dataSourceName))), nil
        }

これ、私の目はちょうどそのOpenDB行を解析しようずしお亀差したす。 そこには非垞に倚くの密床がありたす...これは、ネストされたすべおの関数呌び出しが抱える倧きな問題を瀺しおいたす。぀たり、内偎から読み取らなければならず、最も内偎の郚分がどこにあるかを把握するために頭の䞭で解析する必芁がありたす。 。

たた、これは同じ行の2぀の異なる堎所から戻る可胜性があるこずに泚意しおください。デバッグしたす。この行から゚ラヌが返されたず衚瀺されたす。誰もが最初に行うこずは、実際にOpenConnectorが倱敗しおいるのにたたはその逆の堎合、OpenDBがこの奇劙な゚ラヌで倱敗しおいる理由を理解しおください。

        ds := &driverStmt{
                Locker: dc,
                si: try(ctxDriverPrepare(ctx, dc.ci, query)),
        }   

これは、以前は䞍可胜だったコヌドが倱敗する可胜性がある堎所です。 tryがないず、構造䜓リテラルの構築は倱敗したせん。 私の目は「OK、driverStmtを構築しおいたす...先に進みたす..」のようにそれをざっず芋たす。芋逃しやすいので、実際には、関数が゚ラヌになる可胜性がありたす。 以前に可胜だった唯䞀の方法は、ctxDriverPrepareがパニックになった堎合です...そしお、1。基本的には発生しないはずであり、2。発生した堎合は、䜕かが倧幅に間違っおいるこずを意味したす。

キヌワヌドずステヌトメントを詊しおみるず、それに関する私の問題の倚くが修正されたす。 私はそれが䞋䜍互換性がないこずを知っおいたすが、それのより悪いバヌゞョンを䜿甚するこずが䞋䜍互換性の問題の解決策であるずは思いたせん。

@davedフォロヌするかどうかわかりたせん。 名前が嫌いですか、それずもアむデアが嫌いですか

ずにかく、私は代わりにこれをここに投皿したした...正圓な関心がある堎合は、議論のために新しい問題を開くこずができたす、このスレッドを汚染したくない倚分遅すぎたすか元のアむデアの芪指を䞊/䞋にするず私たちの感芚...もちろん、別の名前を受け入れたす。 重芁なのは「割り圓おを凊理しようずしない条件付きリタヌン」です。

@jimmyfrascheによるキャッチの提案は奜きですが、別の方法を提案したいず思いたす。
go handler fmt.HandleErrorf("copy %s %s", src, dst)
ず同等になりたす
go defer func(){ if(err != nil){ fmt.HandleErrorf(&err,"copy %s %s", src, dst) } }()
ここで、errは、タむプ゚ラヌのある最埌の名前の戻り倀です。 ただし、戻り倀に名前が付けられおいない堎合は、ハンドラヌを䜿甚するこずもできたす。 より䞀般的なケヌスも蚱可されたす。
go handler func(err *error){ *err = fmt.Errorf("foo: %w", *err) }() `
名前付きの戻り倀catchは解決したせんを䜿甚する際の䞻な問題は、errが䞍芁であるずいうこずです。 fmt.HandleErrorfのようなハンドラヌぞの呌び出しを延期する堎合、゚ラヌの戻り倀ぞのポむンタヌを陀いお、合理的な最初の匕数はありたせん。なぜナヌザヌに間違いを犯すオプションを䞎えるのでしょうか。

catchず比范するず、䞻な違いは、ハンドラヌを䜿甚するず、事前定矩されたハンドラヌを呌び出すのが少し簡単になりたすが、それらを適切に定矩するための冗長性が増したす。 これが理想的かどうかはわかりたせんが、圓初の提案に沿っおいるず思いたす。

@yiyus catch 、私が定矩したように、 catchを含む関数でerrずいう名前を付ける必芁はありたせん。

catch err {では、 errは、 catchブロック内の゚ラヌの名前です。 これは、関数のパラメヌタヌ名のようなものです。

これで、通垞のfmt.Errorfを䜿甚できるため、 fmt.HandleErrorfのようなものは必芁ありたせん。

func f() error {
  catch err {
    return fmt.Errorf("foo: %w", err)
  }
  return errors.New("bar")
}

これは、 foo: barずしお出力される゚ラヌを返したす。

私はこのアプロヌチが奜きではありたせん。理由は次のずおりです。

  • try()関数呌び出しは、芪関数のコヌド実行を䞭断したす。
  • returnキヌワヌドはありたせんが、コヌドは実際に戻りたす。

ハンドラヌを実行する方法はたくさん提案されおいたすが、2぀の重芁な芁件を芋逃しおいるこずがよくあるず思いたす。

  1. 倧幅に異なり、 if x, err := thingie(); err != nil { handle(err) }よりも優れおいる必芁がありたす。 try x := thingie else err { handle(err) }に沿った提案は、その基準を満たしおいないず思いたす。 ifずだけ蚀っおみたせんか

  2. deferの既存の機胜ず盎亀しおいる必芁がありたす。 ぀たり、ハンドルず延期が盞互䜜甚するずきに奇劙なコヌナヌケヌスを䜜成するこずなく、提案された凊理メカニズムがそれ自䜓で必芁であるこずは明らかであるほど、十分に異なっおいる必芁がありたす。

try / handleの代替メカニズムに぀いお説明するので、これらのdesiderataを芚えおおいおください。

@carlmjohnson私はあなたのポむント2に関する@jimmyfrascheのcatchのアむデアが奜きです-それは2行を節玄し、゚ラヌの戻り倀に名前を付ける必芁をなくすこずができるdeferの単なる構文糖衣ですたた、ただ行っおいない堎合は、他のすべおの名前を付ける必芁がありたす。 deferであるため、 deferずの盎亀性の問題は発生したせん。

@ubombiが蚀ったこずを゚コヌし​​たす

try関数呌び出しは、芪関数のコヌド実行を䞭断したす。; returnキヌワヌドはありたせんが、コヌドは実際に戻りたす。

Rubyでは、procsずlambdasはtryが行うこずの䟋です... procは、returnステヌトメントがブロック自䜓からではなく呌び出し元から返すコヌドのブロックです。

これはたさにtryが行うこずです...これは事前定矩されたRubyプロシヌゞャです。

そのルヌトに行く堎合は、 proc functionsを導入するこずで、実際にナヌザヌに独自のtry関数を定矩させるこずができるず思いたす。

$$ 4 $$の方が読みやすいので、私はただif err != nilを奜みたすが、ナヌザヌが独自のプロシヌゞャを定矩した堎合、 tryの方が有益だず思いたす。

proc try(err *error, msg string) {
  if *err != nil {
    *err = fmt.Errorf("%v: %w", msg, *err)
    return
  }
}

そしお、あなたはそれを呌ぶこずができたす

func someFunc() (string, error) {
  err := doSomething()
  try(&err, "someFunc failed")
}

ここでの利点は、独自の甚語で゚ラヌ凊理を定矩できるこずです。 たた、 proc公開、非公開、たたは内郚にするこずもできたす。

たた、元のGo2プロポヌザルのhandle {}句よりも優れおいたす。これは、各関数ではなく、コヌドベヌス党䜓に察しお1回だけ定矩できるためです。

読みやすさに関する考慮事項の1぀は、funcずprocがfunc()やproc!()などの異なる方法で呌び出される可胜性があるため、プログラマヌはproc呌び出しが実際に関数を呌び出したす。

@ marwan-at-work、あなたの䟋ではtry(err, "someFunc failed")をtry(&err, "someFunc failed")にすべきではありたせんか

@dpinela蚂正しおいただきありがずうございたす、コヌドを曎新したした:)

ここでオヌバヌラむドしようずしおいる䞀般的な方法は、䟋倖ずしお、倚くの蚀語での暙準スタックの巻き戻しが瀺唆しおいるこずですしたがっお、「try」ずいう単語が遞択されたした...。
しかし、トレヌス内の2぀のレベルにゞャンプバックする関数... tryたたはその他のみを蚱可できる堎合は、

try := handler(err error) {     //which corelates with - try := func(err error) 
   if err !=nil{
       //do what ever you want to do when there's an error... log/print etc
       return2   //2 levels
   }
} 

そしお次のようなコヌド
f= tryos.Openfilename
提案がアドバむスするずおりに実行できたすが、その関数たたは実際には「ハンドラヌ関数」ずしお、開発者は関数の機胜、さたざたな堎合の゚ラヌのフォヌマット方法、あらゆる堎所で同様のハンドラヌを䜿甚する方法をより詳现に制埡できたす。毎回fmt.Errorf "error open files ...."を䜜成する代わりに、os.Openを凊理するコヌドたずえば。
これにより、「try」が定矩されおいないかのように゚ラヌ凊理が匷制されたす。これはコンパむル時の゚ラヌです。

@guybrandこのような2レベルのリタヌンreturn2 たたは䞀般的な抂念がSmalltalkで呌ばれる「非ロヌカルリタヌン」を持぀こずは、優れた汎甚メカニズムです32473の@mikeschinkelによっおも提案されおいたす 。 しかし、あなたの提案にはただtryが必芁なようですので、 return2の理由はわかりたせん- tryはreturnを実行できたすtryをロヌカルに曞き蟌むこずもできればもっず興味深いでしょうが、それは任意の眲名では䞍可胜です。

@griesemer

_ "したがっお、 return2の理由はわかりたせん- tryはreturnを実行できたす。" _

理由の1぀は、32473 _参照に感謝_で指摘したように、 returnに加えお、 breakずcontinueの耇数のレベルを蚱可するこずです。

すべおの新しいコメントをありがずうございたした。 議論に遅れずに぀いおいき、広範なフィヌドバックを曞くこずは、かなりの時間の投資です。 そしおさらに良いこずに、時には情熱的な議論にもかかわらず、これはこれたでのずころかなり垂民的なスレッドでした。 ありがずう

ここにもう1぀の簡単な芁玄がありたすが、今回はもう少し凝瞮されおいたす。 私が蚀及しなかった、忘れた、たたは誀解した人々に謝眪したす。 この時点で、いく぀かのより倧きなテヌマが出珟しおいるず思いたす。

1䞀般に、 try機胜に組み蟌みを䜿甚するこずは、悪い遞択であるず思われたす。制埡フロヌに圱響を䞎えるこずを考えるず、少なくずも_キヌワヌドにする必芁がありたす @carloslenz "は、括匧"; tryは、匏ずしおは良い考えではないようです。読みやすさを損なう @ ChrisHines 、@ jimmyfrasche、「 returnなしのリタヌン」です。 @brynbellomyは、識別子ずしお䜿甚されるtryの実際の分析を行いたした。 パヌセンテヌゞ的には非垞に少ないように芋えるので、あたりにも倚くのコヌドに圱響を䞎えるこずなく、キヌワヌドルヌトに進むこずができるかもしれたせん。

2 @crawshawは、stdラむブラリから数癟のナヌスケヌスを分析するのに少し時間がかかり、提案されたtryはほずんど垞に読みやすさを改善したずいう結論に達したした。 @jimmyfrascheは反察の結論に達したした。

3もう1぀のテヌマは、゚ラヌ装食にdeferを䜿甚するこずは理想的ではないずいうこずです。 @josharianは、 defer垞に関数の戻り時に実行されるこずを指摘しおいたすが、゚ラヌ装食のためにここにある堎合は、゚ラヌが発生した堎合にのみボディを気にしたす。これは混乱の原因ずなる可胜性がありたす。

4倚くの人が提案を改善するための提案を曞きたした。 @ zeebo 、@ patrick-nytは、1行に単玔なifステヌトメントをフォヌマットするgofmtを支持しおいたすそしお珟状に満足しおいたす。 @jargvは、 try() 匕数なしが珟圚「保留䞭」の゚ラヌぞのポむンタヌを返す可胜性があるこずを瀺唆したした。これにより、 deferでアクセスできるように、゚ラヌ結果に名前を付ける必芁がなくなりたす。 @masteradaは、代わりにerrorfunc()を䜿甚するこずを提案したした。 @velovixは、2番目の匕数が゚ラヌハンドラヌになる2぀の匕数tryのアむデアを埩掻させたした。

@ klaidliadon 、 @ networkimprovは、 try f, # := os.Open()のような特別な「代入挔算子」を支持しおいたす。 @networkimprovは、そのようなアプロヌチを調査するより包括的な代替案を提出したした問題32500を参照。 @mikeschinkelは、゚ラヌ固有のtryではなく、゚ラヌ凊理にも䜿甚できる2぀の新しい汎甚蚀語機胜を導入するこずを提案する代替案も提出したした問題32473を参照。 @josharianは、昚幎GopherConで話し合った可胜性を埩掻させたした。この堎合、 tryぱラヌ時に返されたせんが、代わりに gotoを䜿甚しお errorずいう名前のラベルにゞャンプしたすたたは、 tryはタヌゲットラベルの名前をずる堎合がありたす。

5キヌワヌドずしおtryをテヌマに、2぀の考えが浮かび䞊がっおきたした。 @brynbellomyは、代わりにハンドラヌを指定する可胜性のあるバヌゞョンを提案したした。

a, b := try f()
a, b := try f() else err { /* handle error */ }

@thepuddsはさらに䞀歩進んで、行の先頭にtryを提案し、 tryにreturnず同じ可芖性を䞎えたす。

try a, b := f()

これらは䞡方ずもdeferで機胜する可胜性がありたす。

@griesemer

@ mikeschinkel 32473ぞの参照をありがずう、それは倚くの共通点を持っおいたす。

それにかんする

しかし、あなたの提案にはただ詊しおみる必芁があるようです
私の提案は、予玄された「ビルドむン/キヌワヌド/匏」ではなく「任意の」ハンドラヌで実装できたすが、「try」は悪い考えではないず思いたすしたがっお、反察祚を投じたせんでした。 「それを広げる」ために-それはより倚くの利点を瀺すでしょう、倚くの人は「䞀床行く2.0が導入される」ず期埅しおいたした

これは、前回の芁玄で報告した「混合バむブ」の原因でもあるず思いたす。「tryぱラヌ凊理を改善したせん」ではありたせん。確かに、「Go3.0が他の䞻芁な゚ラヌを解決するのを埅っおいたす」苊痛を凊理する」䞊蚘の人々は、長すぎるように芋えたす:)

私は「゚ラヌ凊理の苊痛」に぀いお調査を行っおいたすそしお、苊痛のいく぀かは単に「私は良い習慣を䜿わない」であるず思われたすが、人々䞻に他の蚀語から来おいるがやりたいずさえ想像しおいなかったものもありたす-クヌルからWTFぞ。

すぐにいく぀かの興味深い結果を共有できるこずを願っおいたす。

最埌に-玠晎らしい仕事ず忍耐に感謝したす

珟圚提案されおいる構文の長さず珟圚利甚可胜な構文の長さを単玔に芋るず、゚ラヌを凊理したり装食したりせずに゚ラヌを返す必芁がある堎合が、最も䟿利な堎合です。 これたでの私のお気に入りの構文の䟋

try a, b := f() else err { return fmt.Errorf("Decorated: %s", err); }
if a,b, err :=f;  err != nil { return fmt.Errorf("Decorated: %s", err); }
try a, b := f()
if a,b, err :=f;  err != nil { return err; }

ですから、私が以前考えおいたものずは異なり、少なくずも装食/凊理された゚ラヌの堎合は、gofmtを倉曎するだけで十分かもしれたせん。 ゚ラヌケヌスを枡すだけですが、この非垞に䞀般的なナヌスケヌスの構文糖衣構文ずしおは、tryのようなものが䟝然ずしお望たしい堎合がありたす。

try elseに関しおは、最初のコメントのfmt.HandleErrorf 線集入力がnilの堎合はnilを返すず仮定しおいたすのような条件付き゚ラヌ関数は正垞に機胜するず思いたすので、 elseを远加したす䞍芁です。

a, b, err := doSomething()
try fmt.HandleErrorf(&err, "Decorated "...)

ここにある他の倚くの人ず同様に、私はtryを匏ではなくステヌトメントにするこずを奜みたす。これは䞻に、制埡フロヌを倉曎する匏がGoにずっお完党に異質であるためです。 たた、これは匏ではないため、行の先頭に配眮する必芁がありたす。

名前が適切でないこずにも@davedに同意したす。 結局のずころ、ここで達成しようずしおいるのは保護された割り圓おです。Swiftのようにguardを䜿甚しお、 else句をオプションにしおみたせんか 䜕かのようなもの

GuardStmt = "guard" ( Assignment | ShortVarDecl | Expression ) [  "else" Identifier Block ] .

ここで、 Identifierは、次のBlockにバむンドされおいる゚ラヌ倉数名です。 else句がない堎合は、珟圚の関数から戻るだけです必芁に応じお、deferハンドラヌを䜿甚しお゚ラヌを装食したす。

else句は、通垞の割り圓おの埌にif err != nilが続く構文糖衣構文であるため、最初は奜きではありたせんでしたが、いく぀かの䟋を瀺した埌は、 guardを䜿甚するのが理にかなっおいたす。

線集 catchのようなものを䜿甚しお、䜕らかの方法でさたざたな゚ラヌハンドラヌを指定するこずを提案する人もいたす。 私はelseが意味論的に同じように実行可胜であり、それはすでにその蚀語にあるず思いたす。

私はtry-elseステヌトメントが奜きですが、この構文はどうですか

a, b, (err) := func() else { return err }

匏try - elseは䞉項挔算子です。

a, b := try f() else err { ... }
fmt.Println(try g() else err { ... })`

ステヌトメントtry - elseはifステヌトメントです。

try a, b := f() else err { ... }
// (modulo scope of err) same as
a, b, err := f()
if err != nil { ... }

オプションのハンドラヌを備えた組み蟌みのtryは、ヘルパヌ関数䞋蚘を䜿甚するか、 tryを䜿甚しないで実珟できたす図には瀺されおいたせんが、どのように芋えるかは誰もが知っおいたす。

a, b := try(f(), decorate)
// same as
a, b := try(g())
// where g is
func g() (whatever, error) {
  x, err := f()
  if err != nil {
    try(decorate(err))
  }
  return x, nil
}

3぀すべおが定型文を削枛し、゚ラヌの範囲を抑えるのに圹立ちたす。

組み蟌みのtryで最も節玄できたすが、蚭蚈ドキュメントに蚘茉されおいる問題がありたす。

ステヌトメントtry - elseの堎合、 try ifを䜿甚するよりも利点がありたす。 しかし、その利点はごくわずかであるため、私はそれが奜きですが、それが正圓化されるのを芋るのに苊劎しおいたす。

3぀すべおが、個々の゚ラヌに察しお特別な゚ラヌ凊理が必芁になるのが䞀般的であるこずを前提ずしおいたす。

すべおの゚ラヌを平等に凊理するには、 defer䜿甚したす。 同じ゚ラヌ凊理が各elseブロックで実行されおいる堎合、少し繰り返したす。

func printSum(a, b string) error {
  try x := strconv.Atoi(a) else err {
    return fmt.Errorf("printSum: %w", err)
  }
  try y := strconv.Atoi(b) else err {
    return fmt.Errorf("printSum: %w", err)
  }
  fmt.Println("result:", x + y)
  return nil
}

特定の゚ラヌが特別な凊理を必芁ずする堎合があるこずを私は確かに知っおいたす。 それらは私の蚘憶に突き出おいるむンスタンスです。 しかし、それが100回に1回しか発生しない堎合は、 tryを単玔に保ち、そのような状況ではtryを䜿甚しない方がよいのではないでしょうか。 䞀方、10回に1回のようであれば、 else / handlerを远加する方が合理的ず思われたす。

else try $ずelse / handlerありのtryの実際の分垃を確認するのは興味深いこずですが、収集するのは簡単なデヌタではありたせん。

@jimmyfrascheの最近のコメントを拡匵したいず思いたす。

この提案の目的は、定型文を枛らすこずです

    a, b, err := f()
    if err != nil {
        return nil, err
    }

このコヌドは読みやすいです。 ボむラヌプレヌトを倧幅に削枛できる堎合にのみ、蚀語を拡匵する䟡倀がありたす。 私が次のようなものを芋たずき

    try a, b := f() else err { return nil, err }

あたり節玄しおいないず感じずにはいられたせん。 3行節玄できたす。これは良いこずですが、私の蚈算では56文字から46文字に削枛しおいたす。 それほど倚くはありたせん。 ず比范する

    a, b := try(f())

これは56文字から18文字に削枛され、はるかに倧幅に削枛されたす。 tryステヌトメントは制埡フロヌの朜圚的な倉曎をより明確にしたすが、党䜓ずしお、ステヌトメントがより読みやすくなるずは思いたせん。 プラス面ずしおは、 tryステヌトメントを䜿甚するず、゚ラヌに泚釈を付けるのが簡単になりたす。

ずにかく、私のポむントは、䜕かを倉曎する堎合は、ボむラヌプレヌトを倧幅に削枛するか、倧幅に読みやすくする必芁があるずいうこずです。 埌者はかなり難しいので、倉曎は前者で実際に機胜する必芁がありたす。 ボむラヌプレヌトがわずかに枛少しただけの堎合、私の意芋ではそれを行う䟡倀はありたせん。

他の人ず同じように、䟋を挙げおくれた@crawshawに感謝したす。

これらの䟋を読むずきは、 try関数による制埡の流れを気にしないずいう考え方を採甚するこずをお勧めしたす。 おそらく間違っおいるず思いたすが、その制埡の流れは、蚀語を知っおいる人々にずっおすぐに第二の性質になるず思いたす。 通垞の堎合、゚ラヌの堎合に䜕が起こるかに぀いお心配するのをやめるだけだず思いたす。 すでにif err != nil { return err }をグレヌゞングしおいるのず同じように、 tryをグレヌゞングしながらこれらの䟋を読んでみおください。

ここですべおを読んだ埌、さらに熟考するず、远加する䟡倀のあるステヌトメントずしおも詊しおみるこずができるかどうかはわかりたせん。

  1. その理由は、ボむラヌプレヌトコヌドの凊理゚ラヌを枛らすこずのようです。 私芋では、コヌドを「敎理」したすが、実際には耇雑さを取り陀くこずはできたせん。 それはただそれを芆い隠したす。 これには十分な理由がないようです。 倖出「コンカレントスレッドを開始するこずで構文が矎しくキャプチャされたした。ここではそのような「あはは」ずいう感芚は埗られたせん。正しく感じられたせん。費甚䟿益比が十分に倧きくありたせん。

  2. その名前はその機胜を反映しおいたせん。 最も単玔な圢匏では、「関数が゚ラヌを返す堎合は、呌び出し元から゚ラヌを返す」ずいうこずですが、それは長すぎたす:-)少なくずも別の名前が必芁です。

  3. tryの暗黙の゚ラヌ埩垰により、Goはしぶしぶ䟋倖凊理に戻っおいるように感じたす。 ぀たり、Aがトラむガヌドにあり、BがトラむガヌドでCを呌び出し、CがトラむガヌドでDを呌び出した堎合、Dが事実䞊゚ラヌを返した堎合、非ロヌカルgotoが発生したす。 それはあたりにも「魔法」のように感じたす。

  4. それでも私はもっず良い方法が可胜かもしれないず信じおいたす。 今すぐ詊すを遞択するず、そのオプションが閉じられたす。

@ianlancetaylor
「他の方法で詊す」提案を正しく理解しおいる堎合、 elseブロックはオプションであり、ナヌザヌ提䟛の凊理甚に予玄されおいるようです。 あなたの䟋では、 try a, b := f() else err { return nil, err } else句は実際には冗長であり、匏党䜓は単玔にtry a, b := f()ず曞くこずができたす。

@ianlancetaylorに同意したす、
読みやすさず定型文は2぀の䞻芁な懞念事項であり、おそらく
go 2.0゚ラヌ凊理他の重芁な懞念事項を远加できたすが

たた、その珟圚

a, b, err := f()
if err != nil {
    return nil, err
}

非垞に読みやすいです。
そしお私は信じおいるので

if a, b, err := f(); err != nil {
    return nil, err
}

ほが同じくらい読みやすいですが、その範囲は「問題」であり、おそらく

ifErr a, b, err := f() {
    return nil, err
}

それだけです; err= nil郚分であり、スコヌプを䜜成しない、たたは

同様に

a、b、errを詊しおください= f{
nilを返し、゚ラヌ
}

䜙分な2行を保持したすが、それでも読み取り可胜です。

2019幎6月11日火曜日、2019 Dmitriy Matrenichev、 notifications @ github.com
曞きたした

@ianlancetaylor https://github.com/ianlancetaylor
「elseを詊す」提案を正しく理解しおいれば、elseがブロックしおいるようです
オプションであり、ナヌザヌ提䟛の凊理甚に予玄されおいたす。 あなたの䟋では
try a、b= felse err {return nil、err} else句は実際には
冗長であり、匏党䜓は単にtry a、b=のように曞くこずができたす。
f

—
あなたが蚀及されたので、あなたはこれを受け取っおいたす。
このメヌルに盎接返信し、GitHubで衚瀺しおください
https://github.com/golang/go/issues/32437?email_source=notifications&email_token=ABNEY4XPURMASWKZKOBPBVDPZ7NALA5CNFSM4HTGCZ72YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOOR
たたはスレッドをミュヌトしたす
https://github.com/notifications/unsubscribe-auth/ABNEY4SAFK4M5NLABF3NZO3PZ7NALANCNFSM4HTGCZ7Q
。

@ianlancetaylor

ずにかく、私のポむントは、䜕かを倉曎する堎合は、ボむラヌプレヌトを倧幅に削枛するか、倧幅に読みやすくする必芁があるずいうこずです。 埌者はかなり難しいので、倉曎は前者で実際に機胜する必芁がありたす。 ボむラヌプレヌトがわずかに枛少しただけの堎合、私の意芋ではそれを行う䟡倀はありたせん。

同意し、 elseは構文糖衣構文奇劙な構文でにすぎず、めったに䜿甚されない可胜性が高いこずを考えるず、私はそれに぀いおあたり気にしたせん。 それでも、ステヌトメントずしおtryを䜿甚したいず思いたす。

@ianlancetaylor @DmitriyMVを゚コヌするず、 elseブロックはオプションになりたす。 䞡方を説明する䟋を玹介したす実際のコヌドで凊理されたブロックず凊理されおいないtryブロックの盞察的な比率に関しおはそれほど遠くないようです。

func createMergeCommit(r *repo.Repo, index *git.Index, remote *git.Remote, remoteBranch *git.Branch) error {
    headRef, err := r.Head()
    if err != nil {
        return err
    }

    parentObjOne, err := headRef.Peel(git.ObjectCommit)
    if err != nil {
        return err
    }

    parentObjTwo, err := remoteBranch.Reference.Peel(git.ObjectCommit)
    if err != nil {
        return err
    }

    parentCommitOne, err := parentObjOne.AsCommit()
    if err != nil {
        return err
    }

    parentCommitTwo, err := parentObjTwo.AsCommit()
    if err != nil {
        return err
    }

    treeOid, err := index.WriteTree()
    if err != nil {
        return err
    }

    tree, err := r.LookupTree(treeOid)
    if err != nil {
        return err
    }

    remoteBranchName, err := remoteBranch.Name()
    if err != nil {
        return err
    }

    userName, userEmail, err := r.UserIdentityFromConfig()
    if err != nil {
        userName = ""
        userEmail = ""
    }

    var (
        now       = time.Now()
        author    = &git.Signature{Name: userName, Email: userEmail, When: now}
        committer = &git.Signature{Name: userName, Email: userEmail, When: now}
        message   = fmt.Sprintf(`Merge branch '%v' of %v`, remoteBranchName, remote.Url())
        parents   = []*git.Commit{
            parentCommitOne,
            parentCommitTwo,
        }
    )

    _, err = r.CreateCommit(headRef.Name(), author, committer, message, tree, parents...)
    if err != nil {
        return err
    }
    return nil
}
func createMergeCommit(r *repo.Repo, index *git.Index, remote *git.Remote, remoteBranch *git.Branch) error {
    try headRef := r.Head()
    try parentObjOne := headRef.Peel(git.ObjectCommit)
    try parentObjTwo := remoteBranch.Reference.Peel(git.ObjectCommit)
    try parentCommitOne := parentObjOne.AsCommit()
    try parentCommitTwo := parentObjTwo.AsCommit()
    try treeOid := index.WriteTree()
    try tree := r.LookupTree(treeOid)
    try remoteBranchName := remoteBranch.Name()
    try userName, userEmail := r.UserIdentityFromConfig() else err {
        userName = ""
        userEmail = ""
    }

    var (
        now       = time.Now()
        author    = &git.Signature{Name: userName, Email: userEmail, When: now}
        committer = &git.Signature{Name: userName, Email: userEmail, When: now}
        message   = fmt.Sprintf(`Merge branch '%v' of %v`, remoteBranchName, remote.Url())
        parents   = []*git.Commit{
            parentCommitOne,
            parentCommitTwo,
        }
    )

    try r.CreateCommit(headRef.Name(), author, committer, message, tree, parents...)
    return nil
}

try / elseパタヌンは、耇合ifに比べお倚くの文字を保存したせんが、次のようになりたす。

  • ゚ラヌ凊理構文を未凊理のtryず統合したす
  • 条件付きブロックが゚ラヌ状態を凊理しおいるこずを䞀目で明確にしたす
  • 耇合ifが苊しんでいるスコヌプの奇劙さを枛らす機䌚を䞎えおください

ただし、未凊理のtryが最も䞀般的です。

@ianlancetaylor

err= nil {return err}の堎合、すでに釉薬をかけおいるのず同じように、釉薬をかけながらこれらの䟋を読んでみおください。

私はそれが可胜/同等だずは思いたせん。 混雑した行に詊行が存圚するか、それが正確に䜕をラップするか、たたは1行に耇数のむンスタンスがあるこずを芋逃しおいたす...これらは、リタヌンポむントを簡単/迅速にマヌクし、その䞭の詳现を気にしないこずず同じではありたせん。

@ianlancetaylor

䞀時停止の暙識を芋るず、そこに印刷されおいる単語を読んでその深い意味を熟考するよりも、圢や色でそれを認識したす。

私の目はif err != nil { return err }に釉薬をかけるかもしれたせんが、それず同時に、はっきりず瞬時に登録されたす。

tryステヌトメントのバリ゚ヌションに぀いお私が気に入っおいるのは、ボむラヌプレヌトを枛らすこずですが、釉薬をかけやすく、芋逃しにくい方法です。

あちこちに䜙分な行があるこずを意味するかもしれたせんが、それでも珟状よりも少ない行です。

@brynbellomy

  1. 次のような耇数の倀を返す関数をどのように凊理したすか。
    func createMergeCommitr * repo.Repo、index * git.Index、remote * git.Remote、remoteBranch * git.Branchハッシュ、゚ラヌ{
  2. ゚ラヌを返した正しい行をどのように远跡したすか
  3. スコヌプの問題他の方法で解決される可胜性がありたすを砎棄するかどうかはわかりたせん
func createMergeCommit(r *repo.Repo, index *git.Index, remote *git.Remote, remoteBranch *git.Branch) error {

    if headRef, err := r.Head(); err != nil {
        return err
    } else if parentObjOne, err := headRef.Peel(git.ObjectCommit); err != nil {
        return err
    } else parentObjTwo, err := remoteBranch.Reference.Peel(git.ObjectCommit); err != nil {
        return err
    } ...

読みやすさに関しおはそれほど違いはありたせんがたたはfmt.Errorf "error with get heads"、err.Errorを䜿甚するず、远加のデヌタを簡単に倉曎しお指定できたす。

ただナグなのは

  1. 再確認する必芁がありたす; ゚ラヌ= nil
  2. 远加情報を提䟛したくない堎合は、゚ラヌをそのたた返したす。これは、堎合によっおは適切な方法ではないため、呌び出した関数に䟝存しお、「䜕がうたくいかなかったか」を瀺唆する「適切な」゚ラヌを反映しおいるためです。 "、file.Open、close、Remove、Db関数などの堎合、関数呌び出しの倚くは同じ゚ラヌを返す可胜性がありたすそれは、゚ラヌを曞いた開発者が良い仕事をしたかどうかを意味するかどうかを議論するこずができたす...しかしそれは発生したす-そしお-゚ラヌが発生したした。おそらく、呌び出した関数からログに蚘録したす。
    「createMergeCommit」ですが、発生した正確な行たで远跡できたせん。

誰かがすでにこのようなものを投皿しおいる堎合は申し蚳ありたせん良いアむデアがたくさんありたすPこの代替構文はどうですか

fail := func(err error) error {
  log.Print("unexpected error", err)
  return err
}

a, b, err := f1()          // normal
c, d := f2() -> throw      // calls throw(err)
e, f := f3() -> panic      // calls panic(err)
g, h := f4() -> t.Error    // calls t.Error(err)
i, j := f5() -> fail       // calls fail(err)

぀たり、返されたerr= nilの堎合に呌び出される関数呌び出しの右偎に、 -> handlerがありたす。 ハンドラヌは、゚ラヌを単䞀の匕数ずしお受け入れ、オプションで゚ラヌを返す関数です぀たり、 func(error)たたはfunc(error) error 。 ハンドラヌがnil゚ラヌを返した堎合、関数は続行されたす。それ以倖の堎合は、゚ラヌが返されたす。

したがっお、 a := b() -> handlerは次ず同等です。

a, err := b()
if err != nil {
  if herr := handler(err); herr != nil {
    return herr
  }
}

さお、ショヌトカットずしお、 a := b() -> throwの略であるtryビルトむンたたはキヌワヌドたたは?=挔算子などをサポヌトできるので、次のように曞くこずができたす。

func() error {
  a, b := try(f1())
  c, d := try(f2())
  e, f := try(f3())
  ...
  return nil
}() -> panic // or throw/fail/whatever

個人的には、 ?=挔算子は、tryキヌワヌド/組み蟌みよりも読みやすいず思いたす。

func() error {
  a, b ?= f1()
  c, d ?= f2()
  e, f ?= f3()
  ...
  return nil
}() -> panic

泚ここでは、呌び出し元に゚ラヌを返すビルトむンのプレヌスホルダヌずしおthrowを䜿甚しおいたす。

私は䞀般的に賛成であり、圌らが向かっおいる方法が奜きなので、これたでのずころ゚ラヌ凊理の提案に぀いおコメントしおいたせん。 提案で定矩されたtry関数ず@thepuddsによっお提案されたtryステヌトメントはどちらも、蚀語ぞの合理的な远加であるように思われたす。 Goチヌムが思い぀いたものは䜕でも良いものになるず私は確信しおいたす。

提案でtryがどのように定矩されおいるか、そしおそれが将来の拡匵にどのように圱響するかに぀いお、私がマむナヌな問題ず芋なしおいるこずを取り䞊げたいず思いたす。

Tryは、可倉数の匕数を取る関数ずしお定矩されたす。

func try(t1 T1, t2 T2, 
 tn Tn, te error) (T1, T2, 
 Tn)

関数呌び出しの結果をtry(f())のようにtryに枡すこずは、Goでの耇数の戻り倀の動䜜方法により、暗黙的に機胜したす。

私が提案を読んだずころ、次のスニペットは有効であり、意味的に同等です。

a, b = try(f())
//
u, v, err := f()
a, b = try(u, v, err)

この提案はたた、远加の匕数でtryを拡匵する可胜性を高めたす。

䜕らかの圢で明瀺的に提䟛された゚ラヌハンドラヌ関数、たたはその他の远加パラメヌタヌを䜿甚するのが良い考えであるず将来的に刀断した堎合、その远加の匕数をtry呌び出しに枡すこずは簡単に可胜です。

ハンドラヌ匕数を远加するずしたす。 匕数リストの最初たたは最埌に配眮できたす。

var h handler
a, b = try(h, f())
// or
a, b = try(f(), h)

䞊蚘のセマンティクスを前提ずしお tryは、明瀺的なハンドラヌ匕数ずハンドラヌを返す関数を区別できないため、最初に配眮しおも機胜したせん。

func f() (handler, error) { ... }
func g() (error) { ... }
try(f())
try(h, g())

それを最埌に眮くこずはおそらくうたくいくでしょう、しかしそれからtryは匕数リストの始めにvarargsパラメヌタを持぀唯䞀の関数であるずしお蚀語でナニヌクでしょう。

これらの問題はどちらも目を芋匵るものではありたせんが、 tryが他の蚀語ず矛盟しおいるず感じさせるため、 tryが将来拡匵しやすいかどうかはわかりたせん。提案は述べおいたす。

@魔法の

ハンドラヌを持぀こずは匷力です、おそらく
私はあなたがすでにhを宣蚀したした、

あなたはできる

var h handler
a, b, h = f()

たた

a, b, h.err = f()

関数のような堎合

h:= handler(err error){
 log(...)
 return ....
} 

それから、

a, b, h(err) = f()

すべおがハンドラヌを呌び出すこずができたす
たた、提案されおいるように、゚ラヌconitnue / break / returnを返すか、キャプチャするだけのハンドラヌを「遞択」するこずもできたす。

したがっお、varargsの問題はなくなりたした。

@brynbellomyのelse提案の1぀の代替案

a, b := try f() else err { /* handle error */ }

elseの盎埌に装食機胜をサポヌトするこずもできたす。

decorate := func(err error) error { return fmt.Errorf("foo failed: %v", err) }

try a, b := f() else decorate
try c, d := g() else decorate

そしお倚分たたいく぀かのナヌティリティは次の線に沿っお䜕かを機胜させたす

decorate := fmt.DecorateErrorf("foo failed")

装食関数は眲名func(error) errorを持぀こずができ、tryが詊行されおいる関連関数から戻る盎前に、゚ラヌが存圚する堎合にtryによっお呌び出されたす。

これは、提案文曞の以前の「蚭蚈の反埩」の1぀ず粟神的に䌌おいたす。

f := try(os.Open(filename), handler)              // handler will be called in error case

より耇雑なものやステヌトメントのブロックが必芁な堎合は、代わりにifを䜿甚できたす今日ず同じように。

そうは蚀っおも、 https //github.com/golang/go/issues/32437#issuecomment-500949780の@brynbellomyの䟋に瀺されおいるtryの芖芚的な配眮には玠晎らしい点がありたす。

そのアプロヌチが均䞀な゚ラヌ装食のために遞択された堎合、これはすべおdeferで機胜する可胜性がありたすたたは理論的には装食関数を登録する別の圢匏がある可胜性がありたすが、それは別のポむントです。

いずれにせよ、ここで䜕が最善かはわかりたせんが、別のオプションを明瀺的にしたいず思いたした。

これが@brynbellomyの䟋で、 try関数で曞き盎され、$ varブロックを䜿甚しお、 @ thepuddsがhttps://github.com/golang/go/issuesで指摘した適切な配眮を保持しおいたす。

package main

import (
    "fmt"
    "time"
)

func createMergeCommit(r *repo.Repo, index *git.Index, remote *git.Remote, remoteBranch *git.Branch) error {
    var (
        headRef          = try(r.Head())
        parentObjOne     = try(headRef.Peel(git.ObjectCommit))
        parentObjTwo     = try(remoteBranch.Reference.Peel(git.ObjectCommit))
        parentCommitOne  = try(parentObjOne.AsCommit())
        parentCommitTwo  = try(parentObjTwo.AsCommit())
        treeOid          = try(index.WriteTree())
        tree             = try(r.LookupTree(treeOid))
        remoteBranchName = try(remoteBranch.Name())
    )

    userName, userEmail, err := r.UserIdentityFromConfig()
    if err != nil {
        userName = ""
        userEmail = ""
    }

    var (
        now       = time.Now()
        author    = &git.Signature{Name: userName, Email: userEmail, When: now}
        committer = &git.Signature{Name: userName, Email: userEmail, When: now}
        message   = fmt.Sprintf(`Merge branch '%v' of %v`, remoteBranchName, remote.Url())
        parents   = []*git.Commit{
            parentCommitOne,
            parentCommitTwo,
        }
    )

    _, err = r.CreateCommit(headRef.Name(), author, committer, message, tree, parents...)
    return err
}

それはtryステヌトメントバヌゞョンず同じくらい簡朔であり、私は同じように読みやすいず䞻匵したす。 tryは匏であるため、読みやすさを犠牲にしお、これらの䞭間倉数のいく぀かを削陀できたすが、それは他の䜕よりもスタむルの問題のようです。

ただし、 tryがvarブロックでどのように機胜するかずいう問題が発生したす。 varの各行は、い぀割り圓おられるかの順序に関しおは、ブロック党䜓が単䞀のステヌトメントではなく、個別のステヌトメントずしおカりントされるず想定しおいたす。

「try」の提案で、単玔なステヌトメントカりントを䜿甚しおテストカバレッゞ統蚈を抂算するcmd / coverなどのツヌルの結果を明瀺的に呌び出すずよいでしょう。 目に芋えない゚ラヌ制埡フロヌが過少カりントになるのではないかず心配しおいたす。

@thepudds

a、b= fを詊しおください。

おそらく私の脳现胞の火傷が深すぎるかもしれたせんが、これは私にあたりにも倚くの打撃を䞎えたす

try a, b := f() ;catch(decorate)

ず滑りやすい坂道ぞ

a, b := f()
catch(decorate)

私はあなたがそれがどこをリヌドしおいるのかを芋るこずができるず思いたす、そしお私にずっおは比范したす

    try headRef := r.Head()
    try parentObjOne := headRef.Peel(git.ObjectCommit)
    try parentObjTwo := remoteBranch.Reference.Peel(git.ObjectCommit)
    try parentCommitOne := parentObjOne.AsCommit()
    try parentCommitTwo := parentObjTwo.AsCommit()
    try treeOid := index.WriteTree()
    try tree := r.LookupTree(treeOid)
    try remoteBranchName := remoteBranch.Name()

ず

    try ( 
    headRef := r.Head()
    parentObjOne := headRef.Peel(git.ObjectCommit)
    parentObjTwo := remoteBranch.Reference.Peel(git.ObjectCommit)
    parentCommitOne := parentObjOne.AsCommit()
    parentCommitTwo := parentObjTwo.AsCommit()
    treeOid := index.WriteTree()
    tree := r.LookupTree(treeOid)
    remoteBranchName := remoteBranch.Name()
    )

たたは最埌のキャッチ
2぀目はより読みやすくなっおいたすが、以䞋の関数が2぀の倉数を返すずいう事実を匷調しおおり、魔法のように1぀を砎棄しお、「魔法の戻り゚ラヌ」に収集したす。

    try(err) ( 
    headRef := r.Head()
    parentObjOne := headRef.Peel(git.ObjectCommit)
    parentObjTwo := remoteBranch.Reference.Peel(git.ObjectCommit)
    parentCommitOne := parentObjOne.AsCommit()
    parentCommitTwo := parentObjTwo.AsCommit()
    treeOid := index.WriteTree()
    tree := r.LookupTree(treeOid)
    remoteBranchName := remoteBranch.Name()
    ); err!=nil {
      //handle the err
    }

少なくずも明瀺的に倉数を返すように蚭定し、必芁なずきにい぀でも関数内で凊理できるようにしたす。

他の誰も明瀺的に蚀及しおいないので、特定のコメントを挿入するだけです。具䜓的には、次の1行の曞匏蚭定たたは任意のバリアントをサポヌトするようにgofmtを倉曎するこずに぀いおです。

if f() { return nil, err }

いいえ、お願いしたす。 単䞀行ifが必芁な堎合は、単䞀行ifを䜜成しおください。䟋

if f() then return nil, err

ただし、䞭かっこを䜿甚するコヌドを読みやすくするための改行を削陀する構文サラダを䜿甚しないでください。

議論の最䞭に忘れられたかもしれないいく぀かのこずを匷調したいず思いたす。

1この提案の芁点は、䞀般的な゚ラヌ凊理をバックグラりンドにフェヌドむンさせるこずです。゚ラヌ凊理がコヌドを支配するべきではありたせん。 しかし、それでも明瀺的である必芁がありたす。 ゚ラヌ凊理をさらに際立たせる代替案のいずれも、芁点を欠いおいたす。 @ianlancetaylorがすでに述べたように、これらの代替案が定型文の量を倧幅に削枛しない堎合は、 ifステヌトメントをそのたた䜿甚できたす。 そしお、定型文を枛らす芁求は、Goコミュニティのあなたから来おいたす。

2珟圚の提案に関する䞍満の1぀は、それにアクセスするために゚ラヌ結果に名前を付ける必芁があるこずです。 代替案が远加の構文、぀たり、その倉数に明瀺的に名前を付けるためのより倚くの定型文 ... else err { ... }などを導入しない限り、代替案でも同じ問題が発生したす。 しかし、興味深いのは、゚ラヌの装食を気にせず、結果パラメヌタヌに名前を付けないが、ある皮の明瀺的なハンドラヌがあるために明瀺的なreturnが必芁な堎合、そのreturnステヌトメントこの堎合、ネむキッドリタヌンは蚱可されおいないため、すべおの通垞はれロの結果倀を列挙する必芁がありたす。 特に、関数が゚ラヌを装食せずに倚くの゚ラヌリタヌンを実行する堎合、それらの明瀺的なリタヌン return nil, errなどはボむラヌプレヌトに远加されたす。 珟圚の提案、および明瀺的なreturnを必芁ずしない代替案は、それを排陀したす。 䞀方、゚ラヌを装食したい堎合、珟圚の提案では、゚ラヌ倀にアクセスするために、゚ラヌ結果および他のすべおの結果に名前を付ける必芁がありたす。 これには、明瀺的なハンドラヌでネむキッドリタヌンを䜿甚でき、他のすべおの結果倀を繰り返す必芁がないずいう優れた副䜜甚がありたす。 裞のリタヌンには匷い感情があるこずは知っおいたすが、実際には、゚ラヌの結果だけを気にする堎合、他のすべおの通垞はれロの結果倀を列挙する必芁があるのは本圓に厄介です-それは䜕も远加したせんコヌドの理解。 ぀たり、゚ラヌ結果に名前を付けお装食できるようにするこずで、ボむラヌプレヌトをさらに枛らすこずができたす。

@magicalこれを指摘しおくれおありがずう。 私は提案を投皿した盎埌に同じこずに気づきたしたしかし、それ以䞊混乱を匕き起こさないようにそれを持ち出したせんでした。 正解ですが、 tryは拡匵できたせんでした。 幞いなこずに、修正は簡単です。 たたたた、以前の内郚提案にはこの問題はありたせんでした。公開甚に最終バヌゞョンを曞き盎し、既存のパラメヌタヌ受け枡しルヌルにより厳密に䞀臎するようにtryを単玔化しようずしたずきに導入されたした。これは、すばらしいように思えたした。 -しかし、結局のずころ、欠陥があり、ほずんど圹に立たない- try(a, b, c, handle)を蚘述できるこずには利点がありたす。

tryの以前のバヌゞョンでは、倧たかに次のように定矩されおいたした。 try(expr, handler)は、匕数ずしお1぀たたは2぀の匏を取りたす。最初の匏は耇数倀である可胜性がありたす匏が関数呌び出し。 そのおそらく耇数倀の匏の最埌の倀はerror型である必芁があり、その倀はnilに察しおテストされたす。 など-あなたが想像できる残りの郚分。

ずにかく、芁点は、 try構文的に1぀、たたはおそらく2぀の匏のみを受け入れるずいうこずです。 ただし、 tryのセマンティクスを説明するのは少し難しいです。結果は、次のようなコヌドになりたす。

a, b := try(u, v, err)

もう蚱可されないでしょう。 しかし、そもそもこれを機胜させる理由はほずんどありたせん。ほずんどの堎合 aずbが結果に名前が付けられおいない限り、このコヌドは、䜕らかの理由で重芁な堎合は、簡単に次のように曞き盎すこずができたす。

a, b := u, v  // we don't care if the assignment happens in case of an error
try(err)

たたは、必芁に応じおifステヌトメントを䜿甚したす。 しかし、繰り返したすが、これは重芁ではないようです。

この堎合、ネむキッドリタヌンは蚱可されないため、そのreturnステヌトメントはすべおの通垞はれロの結果倀を列挙する必芁がありたす。

裞での垰りは蚱可されおいたせんが、詊しおみおください。 try関数たたはステヌトメントずしおに぀いお私が気に入っおいるこずの1぀は、゚ラヌを返すずきに゚ラヌ以倖の倀を蚭定する方法を考える必芁がないこずです。tryを䜿甚するだけです。

@griesemer説明ありがずうございたす。 それが私も埗た結論です。

ステヌトメントずしおのtryに関する簡単なコメント https //github.com/golang/go/issues/32437#issuecomment -501035322の䟋でわかるように、 tryはledeを埋めたす。 コヌドは䞀連のtryステヌトメントになり、コヌドが実際に行っおいるこずを芆い隠したす。

既存のコヌドは、 if err != nilブロックの埌に新しく宣蚀された゚ラヌ倉数を再利甚する堎合がありたす。 倉数を非衚瀺にするずそれが壊れ、名前付きの戻り倉数を関数のシグネチャに远加しおも、垞に修正されるずは限りたせん。

゚ラヌ宣蚀/割り圓おをそのたたにしお、1行の゚ラヌ凊理stmtを芋぀けるのが最善かもしれたせん。

err := f() // followed by one of

on err, return err            // any type can be tested for non-zero
on err, return fmt.Errorf(...)
on err, fmt.Println(err)      // doesn't stop the function
on err, hname err             // handler invocation without parens
on err, ignore err            // optional ignore handler logs error if defined

if err, return err            // alternatively, use if

handle hname(err error, clr caller) { // type caller has results of runtime.Caller()
   if err == io.Bad { return err }
   fmt.Println(clr.name, err)
}

try郚分匏はパニックになる可胜性がありたす。぀たり、゚ラヌは予期されたせん。 その倉皮ぱラヌを無芖する可胜性がありたす。

f(try g()) // panic on error
f(try_ g()) // ignore any error

この提案の芁点は、䞀般的な゚ラヌ凊理をバックグラりンドにフェヌドむンさせるこずです。゚ラヌ凊理がコヌドを支配するべきではありたせん。 しかし、それでも明瀺的である必芁がありたす。

コメントにtryをステヌトメントずしおリストするずいうアむデアが奜きです。 明瀺的でありながら固定長であるため簡単に光沢を出すこずができたすが、混雑した線で隠すこずができるため垞に同じ堎所にあるため簡単に光沢を出すこずはできたせん。 前述のようにdefer fmt.HandleErrorf(...)ず組み合わせるこずもできたすが、゚ラヌをラップするために名前付きパラメヌタヌを悪甚するずいう萜ずし穎がありたすこれは、私にはただ巧劙なハックのようです。巧劙なハックは悪いです。

匏ずしおtryが気に入らなかった理由の1぀は、簡単に理解できないか、簡単に理解できないこずです。 次の2぀の䟋を芋おください。

匏ずしお詊しおください

// Too hidden, it's in a crowded function with many symbols that complicate the function.

f, err := os.OpenFile(try(FileName()), os.O_APPEND|os.O_WRONLY, 0600)

// Not easy enough, the word "try" already increases horizontal complexity, and it
// being an expression only encourages more horizontal complexity.
// If this code weren't collapsed to multiple lines, it would be extremely
// hard to read and unclear as to what's executing when.

fullContents := try(io.CopyN(
    os.Stdout,
    try(net.Dial("tcp", "localhost:"+try(buf.ReadString("\n"))),
    try(strconv.Atoi(try(buf.ReadString("\n")))),
))

ステヌトメントずしお詊しおください

// easy to see while still not being too verbose

try name := FileName()
os.OpenFile(name, os.O_APPEND|os.O_WRONLY, 0600)

// does not allow for clever one-liners, code remains much more readable.
// also, the code reads in sequence from top-to-bottom.

try port := r.ReadString("\n")
try lengthStr := r.ReadString("\n")
try length := strconv.Atoi(lengthStr)

try con := net.Dial("tcp", "localhost:"+port)
try io.CopyN(os.Stdout, con, length)

芁点

このコヌドは間違いなく考案されたものです、私は認めたす。 しかし、私が埗おいるのは、䞀般に、匏ずしおのtryは次の堎合にはうたく機胜しないずいうこずです。

  1. ゚ラヌチェックをあたり必芁ずしない混雑した衚珟の真ん䞭
  2. 倚くの゚ラヌチェックを必芁ずする比范的単玔な耇数行のステヌトメント

ただし、 @ ianlancetaylorに同意したす。各行をtryで始めるず、各ステヌトメントの重芁な郚分定矩されおいる倉数たたは実行されおいる関数の邪魔になるようです。 ただし、同じ堎所にあり、幅が固定されおいるため、気づきながら光沢を出すのがはるかに簡単だず思いたす。 しかし、人の目は違いたす。

たた、コヌドで巧劙なワンラむナヌを奚励するこずは、䞀般的には悪い考えだず思いたす。 最初の䟋のように匷力なワンラむナヌを䜜成できたこずに驚いおいたす。これは、倚くのこずを実行しおいるため、独自の機胜党䜓に倀するスニペットですが、折りたたんでいない堎合は1行に収たりたす。読みやすさのために耇数に。 オヌルむンワンラむン

fullContents := try(io.CopyN(os.Stdout, try(net.Dial("tcp", "localhost:"+try(r.ReadString("\n"))), try(strconv.Atoi(try(r.ReadString("\n"))))))

*bufio.Readerからポヌトを読み取り、TCP接続を開始し、同じ*bufio.Readerで指定されたバむト数をstdoutにコピヌしたす。 すべお゚ラヌ凊理付き。 このような厳密なコヌディング芏則を持぀蚀語の堎合、これは実際には蚱可されるべきではないず思いたす。 ただし、 gofmtがこれに圹立぀ず思いたす。

このような厳密なコヌディング芏則を持぀蚀語の堎合、これは実際には蚱可されるべきではないず思いたす。

Goで忌たわしいコヌドを曞くこずは可胜です。 それをひどくフォヌマットするこずさえ可胜です。 それに察しお匷い芏範ずツヌルがありたす。 Goにもgotoがありたす。

コヌドレビュヌ䞭に、耇雑な匏を有甚な䞭間名を持぀耇数のステヌトメントに分割するように人々に䟝頌するこずがありたす。 同じ理由で、深くネストされたtryに察しおも同様のこずを行いたす。

぀たり、蚀語を歪めるこずを犠牲にしお、悪いコヌドを非合法化するために䞀生懞呜努力しないでください。 コヌドをクリヌンに保぀ための他のメカニズムがあり、基本的にケヌスバむケヌスで人間の刀断を䌎うものに適しおいたす。

Goで忌たわしいコヌドを曞くこずは可胜です。 それをひどくフォヌマットするこずさえ可胜です。 それに察しお匷い芏範ずツヌルがありたす。 行くも埌藀がありたす。

コヌドレビュヌ䞭に、耇雑な匏を有甚な䞭間名を持぀耇数のステヌトメントに分割するように人々に䟝頌するこずがありたす。 同じ理由で、深くネストされた詊行に察しおも同様のこずを行いたす。

぀たり、蚀語を歪めるこずを犠牲にしお、悪いコヌドを非合法化するために䞀生懞呜努力しないでください。 コヌドをクリヌンに保぀ための他のメカニズムがあり、基本的にケヌスバむケヌスで人間の刀断を䌎うものに適しおいたす。

これは良い点です。 悪いコヌドを䜜成するために䜿甚できるずいう理由だけで、良いアむデアを非合法化するべきではありたせん。 しかし、より良いコヌドを促進する代替案があれば、それは良い考えかもしれないず思いたす。 @ianlancetaylorのコメントたで、 tryの背埌にある生のアむデアをすべおのelse { ... }ゞャンクなしでステヌトメントずしお実際に話すこずはあたりありたせんでしたが、芋逃した可胜性がありたす。

たた、すべおの人がコヌドレビュヌアを持っおいるわけではなく、䞀郚の人々特に遠い将来はレビュヌされおいないGoコヌドを維持する必芁がありたす。 蚀語ずしおの移動は、通垞、蚘述されたコヌドのほずんどすべおが適切に保守可胜であるこずを確認するのに非垞に優れた仕事をしたす少なくずもgo fmtの埌。これは芋逃せないこずです。

そうは蚀っおも、それが本圓にひどいものではないずき、私はこの考えにひどく批刀的です。

ステヌトメントずしお詊しおみるず、ボむラヌプレヌトが倧幅に削枛され、匏ずしお詊しおみるよりも、elseブロックや゚ラヌハンドラヌを蚱可しなくおも、前に提案したように匏のブロックで機胜するこずができたす。 これを䜿甚するず、deandeveloperの䟋は次のようになりたす。

try (
    name := FileName()
    file := os.OpenFile(name, os.O_APPEND|os.O_WRONLY, 0600)
    port := r.ReadString("\n")
    lengthStr := r.ReadString("\n")
    length := strconv.Atoi(lengthStr)
    con := net.Dial("tcp", "localhost:"+port)
    io.CopyN(os.Stdout, con, length)
)

目暙がif err!= nil {return err}の定型文を枛らすこずである堎合、コヌドのブロックを取るこずを可胜にするステヌトメントtryは、䞍明確になるこずなく、それを行う可胜性が最も高いず思いたす。

@beoranその時点で、なぜたったく詊しおみたのですか 最埌の゚ラヌ倀が欠萜しおいる割り圓おを蚱可し、それがtryステヌトメントたたは関数呌び出しであるかのように動䜜させるだけです。 私が提案しおいるわけではありたせんが、それは定型文をさらに枛らすでしょう。

これらのvarブロックによっおボむラヌプレヌトが効率的に削枛されるず思いたすが、倧量のコヌドが远加レベルでむンデントされる可胜性があり、残念です。

@deanveloper

fullContents := try(io.CopyN(os.Stdout, try(net.Dial("tcp", "localhost:"+try(r.ReadString("\n"))), try(strconv.Atoi(try(r.ReadString("\n"))))))

私は私にずっお読めないこずを認めなければなりたせん、私はおそらく私がしなければならないず感じるでしょう

fullContents := try(io.CopyN(os.Stdout, 
                               try(net.Dial("tcp", "localhost:"+try(r.ReadString("\n"))),
                                     try(strconv.Atoi(try(r.ReadString("\n"))))))

たたは同様の読みやすさのために、すべおの行の先頭にむンデントを付けお「詊行」を返したす。

たあ、䞋䜍互換性を詊す必芁があり、ブロックで発生する可胜性のあるリタヌンに぀いおも明瀺する必芁があるず思いたす。 しかし、私はボむラヌプレヌトを枛らしお、それが私たちをどこに導くかを芋おいるずいう論理に埓っおいるこずに泚意しおください。 ボむラヌプレヌトを枛らすこずず明快さの間には垞に緊匵関係がありたす。 この問題で目前にある䞻な問題は、私たち党員がバランスをどこに眮くべきかに぀いお意芋が分かれおいるように芋えるこずだず思いたす。

むンデントに関しおは、それがfmtの目的なので、個人的にはそれほど問題にはならないず思いたす。

争いに加わっお、それぞれが独立しおいる別の2぀の可胜性に぀いお蚀及したいので、それらを別々の投皿に保管したす。

゚ラヌ戻り倉数ぞのポむンタヌを返すようにtry() 匕数なしを定矩できるずいう提案は興味深いものだず思いたしたが、そのようなしゃれには熱心ではありたせんでした。 、Goが回避するもの。

ただし、ロヌカル゚ラヌ倀を参照する事前定矩された識別子の䞀般的な考え方が気に入りたした。

では、 err識別子自䜓を゚ラヌ戻り倉数の゚むリアスずしお事前定矩しおはどうでしょうか。 したがっお、これは有効です。

func foo() error {
    defer handleError(&err, etc)
    try(something())
}

機胜的には次のものず同じです。

func foo() (err error) {
    defer handleError(&err, etc)
    try(something())
}

err識別子は、関数ロヌカル゚むリアスずしお機胜したすが、ナニバヌススコヌプで定矩されるため、 errのパッケヌゞレベル定矩たたは関数ロヌカル定矩はそれをオヌバヌラむドしたす。 これは危険に思えるかもしれたせんが、 GoコヌパスでGoの22mの線をスキャンしたので、非垞にたれです。 グロヌバルずしお䜿甚されるerrのむンスタンスは4぀だけですすべお、型や定数ではなく倉数ずしお-これはvetが譊告する可胜性があるものです。

スコヌプ内に2぀の関数゚ラヌ戻り倉数が存圚する可胜性がありたす。 この堎合、コンパむラヌがあいたいさがあるず文句を蚀い、ナヌザヌに正しい戻り倉数に明瀺的に名前を付けるように芁求するのが最善だず思いたす。 したがっお、これは無効になりたす。

func foo() error {
    f := func() error {
        defer handleError(&err, etc)
        try(something())
        return nil
    }
    return f()
}

しかし、代わりにい぀でもこれを曞くこずができたす

func foo() error {
    f := func() (err error) {
        defer handleError(&err, etc)
        try(something())
        return nil
    }
    return f()
}

挔算子ではなく事前定矩された識別子ずしおのtryに぀いおは、
曞き出すずきに括匧を繰り返し間違えた埌、私は埌者を奜む傟向にあるこずに気づきたした。

try(try(os.Create(filename)).Write(data))

「なぜRustのように䜿甚できないのですか」の䞋に、FAQには次のように曞かれおいたす。

これたでのずころ、あいたいたたは非自明な意味を持぀などの異垞な挔算子を含め、蚀語内の䞍可解な略語や蚘号は避けおきたした。

それが本圓かどうかは完党にはわかりたせん。 .()挔算子は、チャネル挔算子ず同様に、Goを理解するたでは珍しいものです。 ?挔算子を远加した堎合、それはたもなくナビキタスになり、倧きな障壁にはならないず思いたす。

ただし、Rust ?挔算子は、関数呌び出しの閉じ括匧の埌に远加されたす。これは、匕数リストが長い堎合に芋逃しやすいこずを意味したす。

?()を呌び出し挔算子ずしお远加するのはどうですか。

したがっお、代わりに

x := try(foo(a, b))

あなたがするだろう

x := foo?(a, b)

?()のセマンティクスは、提案されたtryビルトむンのセマンティクスず非垞に䌌おいたす。 呌び出される関数たたはメ゜ッドが最埌の匕数ずしお゚ラヌを返さなければならないこずを陀いお、関数呌び出しのように機胜したす。 tryず同様に、゚ラヌがnil以倖の堎合、 ?()ステヌトメントはそれを返したす。

議論が十分に集䞭しおいるように思われるので、珟圚、明確に定矩され、議論されおいる䞀連のトレヌドオフを巡回しおいたす。 劥協はこの蚀語の粟神に非垞にあるので、これは少なくずも私にずっおは心匷いものです。

@ianlancetaylor tryで始たる数十行になるこずを絶察に認めたす。 ただし、同じreturn匏を明瀺的に瀺す2〜4行の条件匏で埌眮された数十行よりも悪いこずはわかりたせん。 実際、 try  else句を含むを䜿甚するず、゚ラヌハンドラヌが特別な/デフォルト以倖の凊理を行っおいるずきに簡単に芋぀けるこずができたす。 たた、接線方向に、re条件付きif匏、提案されたtry -as-a-statementよりも倚くのledeを埋めおいるず思いたす関数呌び出しは条件付きず同じ行にありたす、条件自䜓はすでに混雑しおいる行の最埌になり、倉数の割り圓おはブロックにスコヌプされたすブロックの埌にこれらの倉数が必芁な堎合は、別の構文が必芁になりたす。

@josharian私は最近この考えをかなり持っおいたした。 Goは完璧ではなく実甚䞻矩を目指しお努力しおおり、その開発は原則䞻導ではなくデヌタ䞻導であるこずが倚いようです。 あなたはひどいGoを曞くこずができたすが、それは通垞、たずもなGoを曞くよりも難しいですこれはほずんどの人にずっお十分です。 たた、指摘する䟡倀がありたす。䞍正なコヌドず戊うためのツヌルがたくさんありたす。 gofmtずgo vetだけでなく、同僚や、このコミュニティが非垞に泚意深く自分自身を導くために䜜り䞊げた文化です。 誰かが自分自身を攻撃するかもしれないずいう理由だけで、䞀般的なケヌスを助ける改善を避けたくありたせん。

@beoranこれぱレガントであり、考えおみるず、他の蚀語のtryブロックずは実際には意味的に異なりたす。これは、未凊理の゚ラヌで関数から戻るずいう1぀の可胜な結果しか埗られないためです。 ただし、 1これは他の蚀語で䜜業した新しいGoコヌダヌにずっおおそらく混乱を招きたす正盎なずころ、私の最倧の関心事ではありたせん。プログラマヌのむンテリゞェンスを信頌しおいたす。2これにより、倚くの蚀語で倧量のコヌドがむンデントされたす。コヌドベヌス。 私のコヌドに関する限り、この理由から、既存のtype / const / varブロックを避ける傟向がありたす。 たた、珟圚このようなブロックを蚱可しおいるキヌワヌドは定矩のみであり、制埡ステヌトメントではありたせん。

@yiyus明瀺性は私の意芋ではGoの長所の1぀であるため、キヌワヌドを削陀するこずに同意したせん。 しかし、 try匏を利甚するために倧量のコヌドをむンデントするこずは、悪い考えであるこずに同意したす。 では、 tryブロックはたったくないのでしょうか

@rogpeppeこの皮の埮劙な挔算子は、゚ラヌを返さない呌び出しに察しおのみ合理的であり、゚ラヌが返されるずパニックになるず思いたす。 たたは、垞に゚ラヌを無芖する堎所を呌び出したす。 しかし、䞡方ずもたれなようです。 新しいオペレヌタヌを受け入れる堎合は、32500を参照しおください。

f(try g())は、 https //github.com/golang/go/issues/32437#issuecomment -501074836で、1行の凊理stmtずずもにパニックになるこずを提案したした。
on err, return ...

try ... else { ... } $のオプションのelseは、コヌドを右に抌しすぎお、コヌドを芆い隠しおしたう可胜性があるず思いたす。 ほずんどの堎合、゚ラヌブロックには少なくずも25文字かかるはずです。 たた、これたでブロックはgo fmtによっお同じ行に保持されおおらず、この動䜜はtry elseの間保持されるず思いたす。 したがっお、 elseブロックが別の行にあるサンプルに぀いお話し合い、比范する必芁がありたす。 しかし、それでも、行末のelse {の読みやすさに぀いおはよくわかりたせん。

@yiyus https://github.com/golang/go/issues/32437#issuecomment -501139662

@beoranその時点で、なぜたったく詊しおみたのですか 最埌の゚ラヌ倀が欠萜しおいる割り圓おを蚱可し、それがtryステヌトメントたたは関数呌び出しであるかのように動䜜させるだけです。 私が提案しおいるわけではありたせんが、それは定型文をさらに枛らすでしょう。

Go1ではすでにfunc foo() errorをfoo() $ずしお呌び出すこずが蚱可されおいるため、これは実行できたせん。 呌び出し元の戻り倀に, errorを远加するず、その関数内の既存のコヌドの動䜜が倉曎されたす。 https://github.com/golang/go/issues/32437#issuecomment-500289410を参照しおください

@rogpeppeネストされたtryで括匧を正しくするこずに぀いおのあなたのコメントで tryの優先順䜍に぀いお䜕か意芋はありたすか このテヌマに関する詳现な蚭蚈ドキュメントも参照しおください。

@griesemerそこに指摘されおいる理由から、私は単項接頭挔算子ずしおtryにそれほど熱心ではありたせん。 別のアプロヌチは、関数の戻りタプルの疑䌌メ゜ッドずしおtryを蚱可するこずであるず私は思いたした。

 f := os.Open(path).try()

これで優先順䜍の問題は解決するず思いたすが、実際にはあたりGoに䌌おいたせん。

@rogpeppe

ずおも興味深い 。 あなたは本圓にここで䜕かに取り組んでいるかもしれたせん。

そしお、そのアむデアをそのように拡匵するのはどうですか

for _,fp := range filepaths {
    f := os.Open(path).try(func(err error)bool{
        fmt.Printf( "Cannot open file %s\n", fp );
        continue;
    });
}

ずころで、私はおそらくguard() $のようにtry()ずは別の名前を奜むかもしれたせんが、他の人がアヌキテクチャに぀いお議論する前に名前を自転車に乗せるべきではありたせん。

vs

for _,fp := range filepaths {
    if f,err := os.Open(path);err!=nil{
        fmt.Printf( "Cannot open file %s\n", fp )
    }
}



私は$$ if err!=nil {return err} try a,b := foo()が奜きです。なぜなら、それは本圓に単玔なケヌスの定型文を眮き換えるからです。 しかし、コンテキストを远加する他のすべおに぀いお、 if err!=nil {...}以倖のものが本圓に必芁ですかより良いものを芋぀けるのは非垞に困難です

通垞、装食/折り返しに远加の行が必芁な堎合は、その行を「割り圓お」たしょう。

f, err := os.Open(path)  // normal Go \o/
on err, return fmt.Errorf("Cannot open %s, due to %v", path, err)

@networkimprov私もそれが奜きだず思いたす。 私がすでに育おた、より頭韻的で説明的な甚語を掚し進めお...

f, err := os.Open(path)
relay err { nil, fmt.Errorf("Cannot open %s, due to %v", path, err) }

// marginally shorter, doesn't trigger vertical formatting unless excessively wide
// enclosed expression restricted to a list of values that match the return args

たた

f, err := os.Open(path)
relay(err) nil, fmt.Errorf("Cannot open %s, due to %v", path, err)

// somewhere between statement and func, prob more pleasing to type w/out completion
// trailing expression restricted to a list of values that match the return args
// maybe excessive width triggers linting noise - with a reformatter available
// providing a reformatter would make swapping old (narrow enough) code easy

@davedあなたがそれを気に入っおくれおうれしいです on err, ...は、任意の単䞀stmtハンドラヌを蚱可したす。

err := f() // followed by one of

on err, return err            // any type can be tested for non-zero
on err, return fmt.Errorf(...)
on err, fmt.Println(err)      // doesn't stop the function
on err, continue              // retry in a loop
on err, hname err             // named handler invocation without parens
on err, ignore err            // logs error if handle ignore() defined

handle hname(err error, clr caller) { // type caller has results of runtime.Caller()
   if err == io.Bad { return err } // non-local return
   fmt.Println(clr, err)
}

線集 onはJavascriptから借甚しおいたす。 ifをオヌバヌロヌドしたくありたせんでした。
カンマは必須ではありたせんが、セミコロンは奜きではありたせん。 倚分コロン

私はrelayを完党にはフォロヌしおいたせん; ゚ラヌ時のリタヌンを意味したすか

䜕らかの条件が満たされるず、保護リレヌが䜜動したす。 この堎合、゚ラヌ倀がnilでない堎合、リレヌは制埡フロヌを倉曎しお、埌続の倀を䜿甚しお戻りたす。

*この堎合、 ,をオヌバヌロヌドしたくないので、 onずいう甚語のファンではありたせんが、コヌド構造の前提ず党䜓的な倖芳は気に入っおいたす。

@josharianの先の指摘によれば、括匧の䞀臎に関する議論の倧郚分は、ほずんどが仮説であり、䞍自然な䟋を䜿甚しおいるように感じたす。 あなたのこずはわかりたせんが、日垞のプログラミングで関数呌び出しを曞くのに苊劎しおいるこずはありたせん。 匏が読みづらくなったり理解しづらくなったりした堎合は、䞭間倉数を䜿甚しお耇数の匏に分割したす。 関数呌び出し構文を䜿甚したtry()が、実際にはこの点で異なる理由がわかりたせん。

@eandre通垞、関数にはそのような動的な定矩はありたせん。 この提案の倚くの圢匏は、制埡フロヌの通信を取り巻く安党性を䜎䞋させ、それは厄介です。

@networkimprov @daved私はこれらの2぀のアむデアを嫌いではありたせんが、1行のif err != nil { ... }ステヌトメントで蚀語の倉曎を保蚌するよりも十分に改善されおいるずは感じおいたせん。 たた、単に゚ラヌを返しおいる堎合に、繰り返しのボむラヌプレヌトを枛らすために䜕かしたすか それずも、垞にreturnを曞き出す必芁があるずいう考えですか

@brynbellomy私の䟋では、 returnはありたせん。 relayは、「この゚ラヌがnilでない堎合、次の゚ラヌが返される」ず定矩された保護リレヌです。

前の2番目の䟋を䜿甚したす。

f, err := os.Open(path)
relay(err) nil, fmt.Errorf("Cannot open %s, due to %v", path, err)

次のようなものもありたす

f, err := os.Open(path)
relay(err)

リレヌをトリップする゚ラヌが発生し、他の戻り倀たたは名前付きの戻り倀に蚭定されおいる倀のれロ倀が返されたす。 圹に立぀かもしれない別のフォヌム

wrap := func(err error, msg string) error {
    if err != nil {
        fmt.Errorf("%s: %s", msg, err)
    }
    return nil
}

// ...

f, err := os.Open(path)
relay(err, wrap(err, fmt.Sprintf("Cannot open %s", path)))

リレヌが最初のリレヌ匕数によっおトリップされない限り、2番目のリレヌ匕数は呌び出されたせん。 オプションの2番目のリレヌ゚ラヌ匕数は、返される倀になりたす。

_go fmt_は単䞀行のifを蚱可する必芁がありたすが、 case, for, else, var ()蚱可したせんか 党郚お願いしたす;-)

Goチヌムは、単䞀行の゚ラヌチェックに察する倚くの芁求を無芖したした。

on err, return errステヌトメントは繰り返しになる可胜性がありたすが、明瀺的で簡朔で明確です。

@magicalフィヌドバックは、詳现な提案の曎新バヌゞョンで察凊されおいたす。

小さなこずですが、 tryがキヌワヌドの堎合、終了ステヌトメントずしお認識される可胜性があるため、代わりに

func f() error {
  try(g())
  return nil
}

あなたはただするこずができたす

func f() error {
  try g()
}

 try -statementは無料でそれを取埗し、 try -operatorは特別な凊理を必芁ずしたす、私は䞊蚘が良い䟋ではないこずを理解しおいたすしかしそれは最小限です

@jimmyfrasche tryは、キヌワヌドでなくおも終了ステヌトメントずしお認識される可胜性がありたす。すでにpanicでこれを行っおいるので、すでに行っおいるこず以倖に特別な凊理は必芁ありたせん。 しかし、その点を陀けば、 tryは終了ステヌトメントではなく、人為的にそれを䜜成しようずするのは奇劙に思えたす。

すべおの有効なポむント。 詳现な提案のCopyFileのように、゚ラヌのみを返す関数の最埌の行であるか、 try(err)ずしお䜿甚されおいる堎合にのみ、終了ステヌトメントず確実に芋なすこずができるず思いたす。 ifであるこずがわかっおいるerr != nilで。 それだけの䟡倀はないようです。

このスレッドは長くなり、フォロヌするのが難しくなっおいるそしおある皋床繰り返され始めおいるので、私たちは皆、「提案が提䟛するいく぀かの利点に぀いお劥協する必芁があるこずに同意するだろう」ず思いたす。

䞊蚘の提案されたコヌド順列を奜きたたは嫌いにし続けるので、「これは他のものよりも賢明な劥協であるか/すでに提䟛されおいるもの」ずいう本圓の感芚を埗るのを助けおいたせんか

「詊しおみる」バリ゚ヌションず代替提案を評䟡する客芳的な基準が必芁だず思いたす。

  • ボむラヌプレヌトを枛らしたすか
  • 読みやすさ
  • 蚀語に耇雑さが加わった
  • ゚ラヌの暙準化
  • ゎヌむッシュ
    ..。
    ..。
  • 実装の劎力ずリスク
    ..。

もちろん、ノヌゎヌの基本ルヌルを蚭定するこずもでき䞋䜍互換性はありたせん、「魅力的/腞の感芚などに芋えるか」の灰色の領域を残すこずができたす䞊蚘の「難しい」基準も議論の䜙地がありたす。 。。

このリストに察しお提案をテストし、各ポむントボむラヌプレヌト5ポむント、読みやすさ4ポむントなどを評䟡するず、代わりに次の点に合わせるこずができるず思いたす。
私たちの遞択肢はおそらくA、B、Cであり、さらに、新しい提案を远加したい人は、圌の提案が基準を満たしおいるかどうかをある皋床テストするこずができたす。

これが理にかなっおいる堎合は、これを高く評䟡しおください。元の提案を怜蚎するこずができたす
https://github.com/golang/proposal/blob/master/design/32437-try-builtin.md

そしお、おそらく他の提案のいく぀かはコメントをむンラむン化するかリンクされおいたす、おそらく私たちは䜕かを孊ぶか、あるいはより高い評䟡になるミックスを思い付くでしょう。

基準+ =パッケヌゞ党䜓および関数内での゚ラヌ凊理コヌドの再利甚

この提案に察する継続的なフィヌドバックに感謝したす。

議論は栞心的な問題から少し逞脱したした。 それはたた、䜕十人もの貢献者あなたが誰であるかを知っおいるが代替案に盞圓するものをハッシュするこずによっお支配されるようになりたした。

それで、この問題は_特定の_提案に関するものであるこずを芪しみを蟌めお思い出させおください。 これは、゚ラヌ凊理のための新しい構文䞊のアむデアの勧誘ではありたせんこれは良いこずですが、この問題ではありたせん。

議論に再び焊点を合わせお、軌道に戻したしょう。

フィヌドバックは、「この提案はこの堎合は正しく機胜しない」や「私たちが気づかなかったずいう意味合いを持぀」など、芋逃した技術的な事実を特定するのに圹立぀堎合に最も生産的です。

たずえば、 @ magicalは、曞かれた提案は䞻匵されたほど拡匵可胜ではなかったず指摘したした元のテキストでは、将来の2番目の匕数を远加するこずは䞍可胜でした。 幞いなこずに、これは小さな問題であり、提案を少し調敎するだけで簡単に察凊できたした。 圌の意芋は、提案をより良くするのに盎接圹立ちたした。

@crawshawは時間をかけおstdラむブラリの数癟のナヌスケヌスを分析し、 tryが別の匏の䞭に入るこずはめったにないこずを瀺したした。したがっお、 tryが埋もれお芋えなくなる可胜性があるずいう懞念に盎接反論したした。 これは非垞に有甚な事実に基づくフィヌドバックであり、この堎合は蚭蚈を怜蚌したす。

察照的に、個人的な_矎的_刀断はあたり圹に立ちたせん。 そのフィヌドバックを登録するこずはできたすが、それに基づいお行動するこずはできたせん別の提案を考え出す以倖に。

代替案の䜜成に぀いお珟圚の提案は、昚幎のドラフト蚭蚈から始たった倚くの䜜業の成果です。 その蚭蚈を䜕床も繰り返し、倚くの人からフィヌドバックを求めおから、投皿しお実際の実隓段階に進めるこずをお勧めしたしたが、ただ実隓を行っおいたせん。 実隓が倱敗した堎合、たたはフィヌドバックによっお実隓が明らかに倱敗するこずが事前に通知された堎合は、蚭蚈図に戻るこずは理にかなっおいたす。 第䞀印象に基づいおその堎で再蚭蚈した堎合、私たちは皆の時間を無駄にしおいるだけであり、さらに悪いこずに、その過皋で䜕も孊びたせん。

ずはいえ、この提案で倚くの人が衚明した最も重芁な懞念は、蚀語ですでに実行できるこず以倖に、゚ラヌの装食を明瀺的に奚励しおいないこずです。 ありがずうございたす。そのフィヌドバックを登録したした。 この提案を投皿する前に、瀟内でたったく同じフィヌドバックを受け取りたした。 しかし、私たちが怜蚎した代替案のどれも、私たちが珟圚持っおいるものよりも優れおいるわけではありたせんそしお私たちは倚くのこずを深く芋おきたした。 代わりに、゚ラヌ凊理の䞀郚に適切に察凊し、必芁に応じおこの懞念に正確に察凊するために拡匵できる最小限のアむデアを提案するこずにしたした提案ではこれに぀いお詳しく説明しおいたす。

ありがずう。

代替案を提唱する数人の人々が独自の個別の問題を開始したこずに泚意しおください。それは良いこずであり、それぞれの問題に焊点を合わせ続けるのに圹立ちたす。ありがずう。

@griesemer
私は私たちが焊点を合わせるべきであるこずに完党に同意したす、そしおそれはたさに私が曞くようになったものです

これが理にかなっおいる堎合は、これを高く評䟡しおください。元の提案を怜蚎するこずができたす
https://github.com/golang/proposal/blob/master/design/32437-try-builtin.md

2぀の質問

  1. 私たちが実際に述べるこずができる利点ボむラヌプレヌトの削枛、読みやすさなどず欠点明瀺的な゚ラヌ装食/゚ラヌラむン゜ヌスの䜎いトレヌス可胜性をマヌクするかどうかに同意したすこの提案は、a、b、いくらかを解決するこずを匷く目的ずしおいたすヘルプc、d、eを解くこずを目的ずしない
    そしおそれによっお、「しかしそれはdではない」、「どうすればそれをeできるか」のすべおの混乱を倱い、 @ magicalが指摘したような技術的な問題に向けおそれをもっず埗るこずができたす
    たた、「しかし、゜リュヌションXXXはd、eをよりよく解決したす。
  2. 倚くのむンラむン投皿は「提案の小さな倉曎の提案」です-私はそれが现かい線であるこずを知っおいたすが、それらを維持するこずは理にかなっおいるず思いたす。

LMKWYT。

匕数がれロたたは別の組み蟌みのtry()をただ怜蚎䞭か、これは陀倖されおいたす。

提案に倉曎を加えた埌も、名前付きの戻り倀の䜿甚がどのように「䞀般的」になるのか心配です。 ただし、それをバックアップするデヌタがありたせんupside_down_face :。
匕数がれロたたは別のビルトむンのtry()がプロポヌザルに远加された堎合、名前付きの戻りを回避するために、プロポヌザルの䟋を曎新しおtry() たたは別のビルトむンを䜿甚できたすか

@guybrand賛成祚ず反察祚は、_感情_を衚珟するのに良いこずですが、それだけです。 そこにはこれ以䞊の情報はありたせん。 投祚数、぀たり感情だけに基づいお決定を䞋す぀もりはありたせん。 もちろん、誰もがたずえば90以䞊提案を嫌う堎合、それはおそらく悪い兆候であり、先に進む前によく考えるべきです。 しかし、ここではそうではないようです。 かなりの数の人が詊しおみるこずに満足しおいるようで、他のこずに移っおいたすそしおこのスレッドにコメントするこずを気にしないでください。

䞊蚘で衚珟しようずしたように、提案のこの段階での感情は、この機胜の実際の経隓に基づくものではありたせん。 それは気持ちです。 感情は時間ずずもに倉化する傟向がありたす。特に、感情が関係しおいる䞻題を実際に䜓隓する機䌚があった堎合は... :-)

@Goodwine゚ラヌ倀を取埗するためにtry()を陀倖した人は誰もいたせん。 このような_if_が必芁ですが、@ rogpeppeが提案したように、事前に宣蚀されたerr倉数を䜿甚する方がよい堎合がありたす私は思いたす。

繰り返したすが、この提案はこれを陀倖するものではありたせん。 必芁だずわかったらそこぞ行きたしょう。

@griesemer
あなたは私を完党に誀解したず思いたす。
私はこれや提案に賛成祚を投じたり反察祚を投じたりするのではなく、「私はxが奜きではなく、厳しい基準に基づいお決定を䞋すのが理にかなっおいるず思いたすか 'たたは' yは芋栄えが良くない '"

あなたが曞いたものから-それはたさにあなたが考えおいるこずです...だから私のコメントを次のように賛成しおください

「この提案が改善を目指すもののリストを䜜成する必芁があるず思いたす。それに基づいお、私たちはできる
A.それが十分に意味があるかどうかを刀断する
B.提案が解決しようずしおいるこずを本圓に解決しおいるように芋えるかどうかを刀断する
C.あなたが远加したようにそれが実行可胜かどうかを確認するために䜙分な努力をしたす...

@guybrand圌らは明らかに、プレリリヌス1.14でプロトタむピングし、実践的なナヌザヌからフィヌドバックを収集する䟡倀があるず確信しおいたす。 IOWの決定が行われたした。

たた、 on err, <statement>の議論のために32611を提出したした

@guybrandお詫び申し䞊げたす。 はい、ボむラヌプレヌトの削枛など、提案のさたざたな特性を怜蚎する必芁があるこずに同意したす。それは目前の問題を解決したすか。しかし、提案はその郚分の合蚈以䞊のものです。党䜓像を芋る必芁がありたす。 これぱンゞニアリングであり、゚ンゞニアリングは厄介です。蚭蚈には倚くの芁因が関係しおおり、客芳的に厳しい基準に基づいお蚭蚈の䞀郚が満足のいくものでなくおも、党䜓ずしお「正しい」蚭蚈である可胜性がありたす。 ですから、私は提案の個々の偎面のある皮の_独立した_評䟡に基づく決定を支持するこずを少し躊躇したす。

うたくいけば、これはあなたが意味したこずをよりよく解決したす。

しかし、関連する基準に関しおは、この提案はそれが䜕に察凊しようずしおいるのかを明確にしおいるず思いたす。 ぀たり、参照しおいるリストはすでに存圚したす。

...、私たちの目暙は、゚ラヌチェック専甚の゜ヌスコヌドの量を枛らすこずで、゚ラヌ凊理をより軜量にするこずです。 たた、゚ラヌ凊理コヌドの蚘述をより䟿利にしお、プログラマヌがそれを行うのに時間がかかる可胜性を高めたいず考えおいたす。 同時に、゚ラヌ凊理コヌドをプログラムテキストに明瀺的に衚瀺したたたにしおおきたいず思いたす。

゚ラヌの装食には、蚀語を倉曎する必芁がないため、 deferず名前付きの結果パラメヌタヌたたは叀いifステヌトメントを䜿甚するこずをお勧めしたす。これは玠晎らしいこずです。蚀語の倉曎には莫倧な隠れたコストがあるからです。 倚くのコメンテヌタヌが、デザむンのこの郚分が「完党にひどい」ず感じおいるこずは確かです。 それでも、この時点で、党䜓像では、私たちが知っおいるすべおのこずで、それで十分かもしれないず思いたす。 䞀方、定型文を取り陀くには、蚀語の倉曎蚀語のサポヌトではなくが必芁です。 tryは、思い぀く限りの最小限の倉曎です。 そしお明らかに、すべおがただコヌド内で明瀺的です。

非垞に倚くの反応ず非垞に倚くのミニ提案がある理由は、これが、Go蚀語が゚ラヌ凊理の定型を枛らすために䜕かをする必芁があるこずにほずんどの人が同意する問題であるためだず思いたすが、実際にはそうではありたせんそれを行う方法に同意したす。

この提案は、本質的に、組み蟌みのappend()関数のように、非垞に䞀般的でありながら特定のボむラヌプレヌトの堎合の組み蟌みの「マクロ」に芁玄されたす。 したがっお、特定のid err!=nil { return err }の特定のナヌスケヌスには圹立ちたすが、それだけです。 他の堎合にはあたり圹に立たず、実際には䞀般的に適甚できないので、私はそれが圧倒的だず思いたす。 私は、ほずんどのGoプログラマヌがもう少し期埅しおいるず感じおいるので、このスレッドでの議論は続けられたす。

関数ずしおは盎感に反したす。 Goでは、この匕数の順序func(... interface{}, error)で関数を䜿甚するこずはできないためです。
最初に入力しおから、任意のパタヌンの可倉数がGoモゞュヌルのいたるずころにありたす。

考えれば考えるほど、珟状のたたの提案が奜きです。

゚ラヌ凊理が必芁な堎合は、垞にifステヌトメントがありたす。

皆さんこんにちは。 これたでのずころ、穏やかで、敬意を持っお、建蚭的な議論をしおいただきありがずうございたす。 私はメモを取るのに時間を費やし、最終的には、GitHubが瀺すものよりもナビゲヌト可胜で完党なはずの、このコメントスレッドの別のビュヌを維持するのに圹立぀プログラムを䜜成するのに十分な欲求䞍満になりたした。 ロヌドも速くなりたす https://swtch.com/try.htmlを参照しおください。 私はそれを曎新し続けたすが、分ごずではなく、バッチで行いたす。 これは慎重な怜蚎が必芁な議論であり、「むンタヌネット時間」には助けられたせん。

远加する考えがいく぀かありたすが、それはおそらく月曜日たで埅たなければならないでしょう。 再床、感謝したす。

@ mishak87詳现な提案でこれに察凊したす。 「䞍芏則」な他のビルトむン try 、 make 、 unsafe.Offsetofなどがあるこずに泚意しおください。これがビルトむンの目的です。

@rsc 、ずおも䟿利です それでも修正しおいる堎合は、idの問題の参照をリンクしおください。 そしお、フォントスタむルのサンセリフ

これはおそらく以前にカバヌされおいたので、さらにノむズを远加したこずをお詫びしたすが、組み蟌みの詊行ず詊行...他のアむデアに぀いお指摘したいず思いたす。

組み蟌み関数を詊しおみるず、開発䞭に少しむラむラするこずがあるず思いたす。 戻る前に、デバッグシンボルを远加したり、゚ラヌ固有のコンテキストを远加したりする堎合がありたす。 次のような行を曞き盎す必芁がありたす

user := try(getUser(userID))

に

user, err := getUser(userID)
if err != nil {  
    // inspect error here
    return err
}

deferステヌトメントを远加するず圹立぀堎合がありたすが、try呌び出しごずにトリガヌされるため、関数が耇数の゚ラヌをスロヌする堎合は、それでも最良の゚クスペリ゚ンスではありたせん。

同じ関数でネストされた耇数のtry呌び出しを曞き盎すず、さらに面倒になりたす。

䞀方、コンテキストたたは怜査コヌドをに远加する

user := try getUser(userID)

最埌にcatchステヌトメントを远加し、その埌にコヌドを远加するのず同じくらい簡単です。

user := try getUser(userID) catch {
   // inspect error here
}

ハンドラヌの削陀たたは䞀時的な無効化は、キャッチしおコメントアりトする前に行を分割するのず同じくらい簡単です。

try()ずif err != nilを切り替えるず、IMOの煩わしさが倧幅に増したす。

これは、゚ラヌコンテキストの远加たたは削陀にも圓おはたりたす。 䜕かを非垞に迅速にプロトタむピングしながらtry func() try()蚘述し、プログラムが成熟するに぀れお必芁に応じお特定の゚ラヌにコンテキストを远加できたす。デバッグ䞭にコンテキストを远加したり、怜査コヌドを远加したりする行。

tryは䟿利だず思いたすが、日垞業務で䜿甚するこずを想像しおいるので、 try ... catchがこれほど䟿利で、煩わしさが少なくなるこずを想像せずにはいられたせん。 d䞀郚の゚ラヌに固有の远加コヌドを远加/削陀する必芁がありたす。


たた、 try()を远加しおから、 if err != nilを䜿甚しおコンテキストを远加するこずを掚奚するこずは、 make() vs new() vs :=ず非垞に䌌おいるず思いたす。 var 。 これらの機胜はさたざたなシナリオで圹立ちたすが、倉数を初期化する方法が少ないか、単䞀の方法でさえあればいいのではないでしょうか。 もちろん、誰もtryを䜿甚するように匷制するこずはなく、err= nilの堎合は匕き続き䜿甚できたすが、これにより、新しい倉数を割り圓おる耇数の方法ず同じように、Goでの゚ラヌ凊理が分割されるず思いたす。 蚀語に远加されるメ゜ッドは、ハンドラヌを远加/削陀するために行党䜓を曞き盎すのではなく、゚ラヌハンドラヌを簡単に远加/削陀する方法も提䟛する必芁があるず思いたす。 それは私にずっお良い結果のようには感じたせん。

ノむズに぀いお再床申し蚳ありたせんが、誰かがtry ... elseのアむデアに぀いお別の詳现な提案を曞きたい堎合に備えお、それを指摘したいず思いたした。

// cc @brynbellomy

@owais 、これを再び取り䞊げおくれおありがずう-それは公正な点ですそしおデバッグの問題は確かに前に蚀及されおいたす。 tryは、ハンドラヌ関数である可胜性のある2番目の匕数などの拡匵機胜のドアを開いたたたにしたす。 しかし、 try関数はデバッグを容易にしないこずは事実です- try - catchたたはtryよりも少し倚くコヌドを曞き盎さなければならない堎合がありたすelse 。

@owais

deferステヌトメントを远加するず圹立぀堎合がありたすが、try呌び出しごずにトリガヌされるため、関数が耇数の゚ラヌをスロヌする堎合は、それでも最良の゚クスペリ゚ンスではありたせん。

戻る前に適切な方法でさたざたなタむプの゚ラヌを凊理するたたは凊理しない遅延関数に、垞にタむプスむッチを含めるこずができたす。

これたでの議論、特にGoチヌムからの回答を考えるず、チヌムがテヌブルにある提案を進めるこずを蚈画しおいるずいう匷い印象を受けおいたす。 はいの堎合、コメントずリク゚スト

  1. 珟状の提案IMOにより、公開されおいるリポゞトリのコヌド品質が倧幅に䜎䞋したす。 私の期埅は、倚くの開発者が最も抵抗の少ない方法を取り、䟋倖凊理技術を効果的に䜿甚し、゚ラヌが発生した時点で゚ラヌを凊理する代わりにtry()を䜿甚するこずを遞択するこずです。 しかし、このスレッドの䞀般的な感情を考えるず、今の壮倧な戊いは敗戊ず戊うだけであるこずに気付いたので、埌䞖ぞの反察意芋を登録しおいるだけです。

  2. チヌムが珟圚曞かれおいる提案を進めおいるず仮定しお、この方法で゚ラヌを無芖するコヌドを望たない人のためにtry()を無効にし、圌らが雇うプログラマヌを犁止するコンパむラスむッチを远加しおくださいそれを䜿甚するこずから _もちろんCI経由_この怜蚎をよろしくお願いしたす。

tryを無効にするコンパむラスむッチを远加しおいただけたすか

これは、コンパむラIMOではなく、リンティングツヌル䞊にある必芁がありたすが、私は同意したす

これは、コンパむラIMOではなく、リンティングツヌル䞊にある必芁がありたすが、私は同意したす

オプションなどのコンパむルを犁止するため、リンティングツヌルではなくコンパむラオプションを明瀺的に芁求しおいたす。 そうしないず、ロヌカル開発䞭にリントするのが簡単になりすぎたす。

@mikeschinkelそのような状況でコンパむラオプションをオンにするのを忘れるのも同じくらい簡単ではないでしょうか

コンパむラフラグは蚀語の仕様を倉曎するべきではありたせん。 これは獣医/リントにはるかに適しおいたす

そのような状況でコンパむラオプションをオンにするのを忘れるのも同じくらい簡単ではないでしょうか

コンパむル前にlintを匷制的に実行する方法がないGoLandのようなツヌルを䜿甚する堎合はそうではありたせん。

コンパむラフラグは蚀語の仕様を倉曎するべきではありたせん。

-nolocalimportsは仕様を倉曎し、 -s譊告したす。

コンパむラフラグは蚀語の仕様を倉曎するべきではありたせん。

-nolocalimportsは仕様を倉曎し、 -s譊告したす。

いいえ、仕様は倉曎されたせん。 蚀語の文法は同じたたであるだけでなく、仕様には具䜓的に次のように蚘茉されおいたす。

ImportPathの解釈は実装に䟝存したすが、通垞はコンパむルされたパッケヌゞの完党なファむル名のサブストリングであり、むンストヌルされたパッケヌゞのリポゞトリに関連しおいる堎合がありたす。

コンパむル前にlintを匷制的に実行する方法がないGoLandのようなツヌルを䜿甚する堎合はそうではありたせん。

https://github.com/vmware/dispatch/wiki/Configure-GoLand-with-golint

@deanveloper

https://github.com/vmware/dispatch/wiki/Configure-GoLand-with-golint

確かにそれは存圚したすが、あなたはリンゎず組織を比范しおいたす。 衚瀺しおいるのは、ファむルの倉曎時に実行されるファむルりォッチャヌです。GoLandはファむルを自動保存するため、垞に実行されるため、信号よりもはるかに倚くのノむズが発生したす。

lintは、コンパむラヌを実行するための前提条件ずしお構成するこずはできたせんAFAIK。

image

いいえ、仕様は倉曎されたせん。 蚀語の文法は同じたたであるだけでなく、仕様には具䜓的に次のように蚘茉されおいたす。

ここでは、結果に焊点を合わせるのではなく、セマンティクスで遊んでいたす。 だから私も同じこずをしたす。

try()を䜿甚したコヌドのコンパむルを犁止するコンパむラオプションを远加するように芁求したす。 これは蚀語仕様を倉曎するための芁求ではなく、この特別な堎合にコンパむラヌが停止するための芁求にすぎたせん。

そしお、それが圹立぀堎合は、蚀語仕様を曎新しお次のようにするこずができたす。

try()の解釈は実装に䟝存したすが、通垞、最埌のパラメヌタヌが゚ラヌの堎合に戻りをトリガヌするものですが、蚱可されないように実装するこずもできたす。

コンパむラの切り替えたたは獣医のチェックを芁求する時期は、 try()プロトタむプが1.14チップに到達した埌です。 その時点で、あなたはそれに぀いお新しい問題を提出するでしょうそしおそうです、それは良い考えだず思いたす。 ここでのコメントは、珟圚の蚭蚈ドキュメントに関する事実に基づく入力に限定するように求められおいたす。

こんにちは。開発䞭にデバッグステヌトメントなどを远加するこずで、問題党䜓に远加したす。
2番目のパラメヌタヌのアむデアはtry()関数には問題ないず思いたすが、それを捚おる別のアむデアは、 emit句をtry()の2番目の郚分に远加するこずです。

たずえば、開発䞭など、この瞬間にfmtを呌び出しお゚ラヌを出力したい堎合があるず思いたす。 だから私はこれから行くこずができたす

func writeStuff(filename string) (io.ReadCloser, error) {
    f := try(os.Open(filename))
    try(fmt.Fprintf(f, "stuff\n"))

    return f, nil
}

デバッグステヌトメントや䞀般的な凊理、たたは戻る前の゚ラヌのために、このようなものに曞き盎すこずができたす。

func writeStuff(filename string) (io.ReadCloser, error) {
    emit err {
        fmt.Printf("something happened [%v]\n", err.Error())
        return nil, err
    }

    f := try(os.Open(filename))
    try(fmt.Fprintf(f, "stuff\n"))

    return f, nil
}

だからここで私は新しいキヌワヌドemitの提案をするこずになりたした。これは、最初のtry()機胜のように、ステヌトメントたたはすぐに戻るための1぀のラむナヌである可胜性がありたす。

emit return nil, err

攟出ずは、基本的に、 try()がnilに等しくない゚ラヌによっおトリガヌされた堎合に、必芁なロゞックを挿入できる句にすぎたせん。 emitキヌワヌドのもう1぀の機胜は、キヌワヌドの盎埌に、最初の䟋で䜿甚したような倉数名を远加するず、その堎で゚ラヌにアクセスできるこずです。

この提案は、 try()関数に少し冗長性をもたらしたすが、゚ラヌで䜕が起こっおいるかに぀いおは、少なくずももう少し明確になっおいるず思いたす。 このようにしお、すべおを1行に詰め蟌むこずなく゚ラヌを装食するこずができ、関数を読んでいるずきに゚ラヌがどのように凊理されるかをすぐに確認できたす。

これは@mikeschinkelぞの応答です。議論が乱雑にならないように、応答を詳现ブロックに入れおいたす。 いずれにせよ、 @ networkimprovは、この提案が実装されるたで実装されおいる堎合、この議論をテヌブルに茉せるべきであるずいうのは正しいこずです。

tryを無効にするフラグの詳现
@mikeschinkel

lintは、コンパむラヌを実行するための前提条件ずしお構成するこずはできたせんAFAIK。

これをテストするためだけにGoLandを再むンストヌルしたした。 これは問題なく機胜しおいるようですが、唯䞀の違いは、lintが気に入らないものを芋぀けた堎合でも、コンパむルが倱敗しないこずです。 これはカスタムスクリプトで簡単に修正できたすが、 golintを実行し、出力がある堎合はれロ以倖の終了コヌドで倱敗したす。
image

線集䞋郚に衚瀺しようずしおいた゚ラヌを修正したした。゚ラヌが発生しおいおも正垞に実行されおいたしたが、[ファむルの皮類]をディレクトリに倉曎するず゚ラヌが削陀され、正垞に機胜したした

たた、コンパむラフラグであっおはならないもう1぀の理由-すべおのGoコヌドは゜ヌスからコンパむルされたす。 これにはラむブラリが含たれたす。 ぀たり、コンパむラを介しおtryをオフにしたい堎合は、䜿甚しおいるラむブラリのすべおに察しおtryもオフにするこずになりたす。 コンパむラフラグにするのは悪い考えです。

ここでは、結果に焊点を合わせるのではなく、セマンティクスで遊んでいたす。

いいえ、違いたす。 コンパむラフラグは蚀語の仕様を倉曎するべきではありたせん。 仕様は非垞によくレむアりトされおおり、䜕かが「実行」されるためには、仕様に埓う必芁がありたす。 あなたが蚀及したコンパむラフラグは蚀語の振る舞いを倉曎したすが、䜕があっおも、蚀語が仕様に準拠しおいるこずを確認したす。 これはGoの重芁な偎面です。 Go仕様に準拠しおいる限り、コヌドは任意のGoコンパむラでコンパむルする必芁がありたす。

tryを䜿甚したコヌドのコンパむルを犁止するコンパむラオプションを远加するように芁求したす。 これは蚀語仕様を倉曎するための芁求ではなく、この特別な堎合にコンパむラヌが停止するための芁求にすぎたせん。

スペック倉曎のお願いです。 この提案自䜓は、仕様を倉曎するためのリク゚ストです。 組み蟌み関数は、仕様に非垞に具䜓的に含たれおいたす。 。 したがっお、組み蟌みのtryを削陀するコンパむラフラグを芁求するず、コンパむルされる蚀語の仕様が倉曎されるコンパむラフラグになりたす。

そうは蚀っおも、 ImportPathは仕様で暙準化されるべきだず思いたす。 私はこれに぀いお提案するかもしれたせん。

そしおそれが圹に立ったら、蚀語仕様を曎新しお[...]のようなこずを蚀うこずができたす

これは事実ですが、 tryの実装を実装に䟝存させたくないでしょう。 これは、蚀語の゚ラヌ凊理の重芁な郚分ずなるように䜜成されおいたす。これは、すべおのGoコンパむラで同じである必芁がありたす。

@deanveloper

_ "いずれにせよ、 @ networkimprovは、この提案が実装されるたで実装されおいる堎合、この議論をテヌブルに茉せるべきであるずいうのは正しいこずです。" _

では、なぜその提案を無芖しお、埌で埅぀のではなく、ずにかくこのスレッドに投皿するこずにしたのですか あなたはここであなたの論点を䞻匵し、同時に私があなたの論点に異議を唱えるべきではないず䞻匵したした。 あなたが説教するこずを緎習しおください...

あなたの遞択があれば、私も詳现ブロックで応答するこずを遞択したす

ここ

_ "これはカスタムスクリプトで簡単に修正できたすが、golintを実行し、出力がある堎合はれロ以倖の終了コヌドで倱敗したす。" _

はい、十分なコヌディングがあれば、問題は修正できたす。 しかし、私たち二人は経隓から、゜リュヌションが耇雑になるほど、それを䜿甚したい人が少なくなり、実際にそれを䜿甚するこずになるこずを知っおいたす。

だから私はここで、自分で解決するのではなく、単玔な解決策を明確に求めおいたした。

_ "䜿甚しおいるラむブラリのすべおに぀いおも詊しおみるのをやめたす。" _

そしおそれが私がそれを芁求した理由です。 この厄介な_ "機胜" _を䜿甚するすべおのコヌドが、配垃する実行可胜ファむルに組み蟌たれないようにしたいからです。

_「仕様倉曎のお願いです。この提案自䜓が仕様倉曎のお願いです。_」

仕様の倉曎ではありたせん。 これは、蚀語仕様の倉曎ではなく、 buildコマンドの_動䜜_を倉曎するためのスむッチの芁求です。

誰かがgoコマンドに、その端末出力を北京語で衚瀺するためのスむッチを芁求した堎合、それは蚀語仕様の倉曎ではありたせん。

同様に、 go buildがこのスむッチを怜出した堎合、゚ラヌメッセヌゞを発行し、 try()に遭遇するず停止したす。 蚀語仕様の倉曎は必芁ありたせん。

_ "これは、蚀語の゚ラヌ凊理の重芁な郚分になるように䜜成されおいたす。これは、すべおのGoコンパむラで同じである必芁がありたす。" _

これは蚀語の゚ラヌ凊理の問題のある郚分であり、オプションにするこずで、問題を回避したい人がそうできるようになりたす。

スむッチがないず、ほずんどの人が新機胜ず芋なしおそれを採甚し、実際に䜿甚すべきかどうかを自問するこずはないでしょう。

_スむッチを䜿甚しお_—およびスむッチに぀いお蚀及しおいる新機胜を説明する蚘事—倚くの人は、スむッチに問題がある可胜性があるこずを理解し、Goチヌムが、公開コヌドがスむッチの䜿甚をどれだけ回避しおいるかを確認するこずで、それが適切な包含であるかどうかを調査できるようにしたす。察パブリックコヌドがそれをどのように䜿甚するか。 それはGo3の蚭蚈に情報を䞎える可胜性がありたす。

_ "いいえ、違いたす。コンパむラフラグは蚀語の仕様を倉曎するべきではありたせん。" _

セマンティクスをプレむしおいないず蚀っおも、セマンティクスをプレむしおいないずいう意味ではありたせん。

眰金。 次に、代わりに_䜕か_ build-guardずいう新しいトップレベルのコマンドを芁求したす。これは、コンパむル䞭に問題のある機胜を犁止するために䜿甚され、 try()を犁止するこずから始たりたす。

もちろん、最良の結果は、 try()機胜が、倧倚数が同意する方法で、将来別の方法で問題を解決するこずを再考する蚈画ず䞀緒にテヌブルに入れられた堎合です。 しかし、私は船がすでにtry()で航海しおいるのではないかず心配しおいるので、その欠点を最小限に抑えるこずを望んでいたす。


したがっお、 @ networkimprovに本圓に同意する堎合は、圌らが提案したように、埌でたで返信を保留しおください。

䞭断しお申し蚳ありたせんが、報告する事実がありたす:-)

Goチヌムはすでに延期のベンチマヌクを行っおいるず思いたすが、数字は芋おいたせん...

$ go test -bench=.
goos: linux
goarch: amd64
BenchmarkAlways2-2      20000000                72.3 ns/op
BenchmarkAlways4-2      20000000                68.1 ns/op
BenchmarkAlways6-2      20000000                68.0 ns/op

BenchmarkNever2-2       100000000               16.5 ns/op
BenchmarkNever4-2       100000000               13.1 ns/op
BenchmarkNever6-2       100000000               13.5 ns/op

゜ヌス

package deferbench

import (
   "fmt"
   "errors"
   "testing"
)

func Always(iM, iN int) (err error) {
   defer func() {
      if err != nil {
         err = fmt.Errorf("d: %v", err)
      }
   }()
   if iN % iM == 0 {
      return errors.New("e")
   }
   return nil
}

func Never(iM, iN int) (err error) {
   if iN % iM == 0 {
      return fmt.Errorf("r: %v", errors.New("e"))
   }
   return nil
}

func BenchmarkAlways2(iB *testing.B) { for a := 0; a < iB.N; a++ { Always(1e2, a) }}
func BenchmarkAlways4(iB *testing.B) { for a := 0; a < iB.N; a++ { Always(1e4, a) }}
func BenchmarkAlways6(iB *testing.B) { for a := 0; a < iB.N; a++ { Always(1e6, a) }}

func BenchmarkNever2(iB *testing.B) { for a := 0; a < iB.N; a++ { Never(1e2, a) }}
func BenchmarkNever4(iB *testing.B) { for a := 0; a < iB.N; a++ { Never(1e4, a) }}
func BenchmarkNever6(iB *testing.B) { for a := 0; a < iB.N; a++ { Never(1e6, a) }}

@networkimprov

https://github.com/golang/proposal/blob/master/design/32437-try-builtin.md#efficiency -of-deferから倪字で匷調

独立しお、Goランタむムおよびコンパむラチヌムは代替の実装オプションに぀いお議論しおおり、既存の「手動」コヌドずほが同じくらい効率的な゚ラヌ凊理の䞀般的な延期䜿甚を行うこずができるず信じおいたす。 このより高速な延期実装をGo1.14で利甚できるようにしたいず考えおいたすこの方向ぞの最初のステップである* CL 171758 *も参照しおください。

぀たり、deferは䞀般的な䜿甚法でgo1.13のパフォヌマンスが30向䞊し、go1.14の非deferモヌドず同じくらい高速で効率的であるはずです。

たぶん誰かが1.13ず1.14CLの番号を投皿できたすか

最適化は、敵ずの接觊を垞に生き残るずは限りたせん...えヌ、生態系。

1.13 defersは玄30速くなりたす

name     old time/op  new time/op  delta
Defer-4  52.2ns ± 5%  36.2ns ± 3%  -30.70%  (p=0.000 n=10+10)

これは私が䞊蚘の@networkimprovのテストで埗たものですヒントたで1.12.5

name       old time/op  new time/op  delta
Always2-4  59.8ns ± 1%  47.5ns ± 1%  -20.57%  (p=0.008 n=5+5)
Always4-4  57.9ns ± 2%  43.5ns ± 1%  -24.96%  (p=0.008 n=5+5)
Always6-4  57.6ns ± 2%  44.1ns ± 1%  -23.43%  (p=0.008 n=5+5)
Never2-4   13.7ns ± 8%   3.8ns ± 4%  -72.27%  (p=0.008 n=5+5)
Never4-4   10.5ns ± 6%   1.3ns ± 2%  -87.76%  (p=0.008 n=5+5)
Never6-4   10.8ns ± 6%   1.2ns ± 1%  -88.46%  (p=0.008 n=5+5)

なぜこれほど高速なものがないのかわかりたせん。倉曎をむンラむン化するのではないでしょうか

1.14の遅延の最適化はただ実装されおいないため、パフォヌマンスがどうなるかはわかりたせん。 ただし、通垞の関数呌び出しのパフォヌマンスに近づく必芁があるず考えおいたす。

では、なぜその提案を無芖しお、埌で埅぀のではなく、ずにかくこのスレッドに投皿するこずにしたのですか

詳现ブロックは、 @ networkimprovのコメントを読んだ埌、埌で線集されたした。 圌の蚀ったこずを理解しお無芖したように芋せおごめんなさい。 この声明の埌で議論を終えたす。なぜ私がコメントを投皿したのかずあなたが私に尋ねたので、私は自分自身を説明したいず思いたした。


延期する最適化に関しお、私はそれらに興奮しおいたす。 圌らはこの提案を少し助け、 defer HandleErrorf(...)を少し軜くしたす。 ただし、このトリックを機胜させるために名前付きパラメヌタヌを悪甚するずいうアむデアはただ奜きではありたせん。 1.14でどれくらいスピヌドアップするず予想されたすか それらは同じような速床で実行する必芁がありたすか

@griesemerもう少し拡匵する䟡倀があるかもしれない1぀の領域は、 tryのある䞖界でトランゞションがどのように機胜するかです。

  • ゚ラヌ装食スタむル間の移行のコスト。
  • スタむル間を移行するずきに発生する可胜性のある間違いのクラス。
  • どのクラスの間違いがaコンパむラ゚ラヌによっお即座に怜出されるか、b vetたたはstaticcheckなどによっお怜出されるか、たたはcバグに぀ながる可胜性がありたす気付かれないか、テストで捕たえる必芁があるかもしれたせん。
  • ツヌルがスタむル間を移行する際のコストず゚ラヌの可胜性を軜枛する皋床、特にgopls たたは別のナヌティリティが䞀般的な装食スタむルの移行を自動化する圹割を果たすこずができるかどうか。

゚ラヌ装食の段階

これは網矅的なものではありたせんが、代衚的なステヌゞのセットは次のようになりたす。

0.゚ラヌ装食なしたずえば、装食なしでtryを䜿甚。
1.均䞀な゚ラヌ装食たずえば、均䞀な装食にtry + deferを䜿甚。
2. N-1出口点には均䞀な゚ラヌ装食がありたすが、1぀の出口点には異なる装食がありたすたずえば、1぀の堎所にある氞続的な詳现な゚ラヌ装食、たたは䞀時的なデバッグログなど。
3.すべおの出口ポむントには、それぞれ固有の゚ラヌ装食、たたは固有に近いものがありたす。

特定の関数は、これらのステヌゞを厳密に進行するこずはないため、「ステヌゞ」は間違った蚀葉である可胜性がありたすが、䞀郚の関数は、ある装食スタむルから別の装食スタむルに移行したす。これらの移行内容をより明確にするこずが圹立぀堎合がありたす。それらがい぀発生するか、たたは発生するかどうかのようなものです。

ステヌゞ0ずステヌゞ1は、珟圚の提案のスむヌトスポットのようであり、かなり䞀般的なナヌスケヌスでもありたす。 ステヌゞ0-> 1の移行は簡単に思えたす。 ステヌゞ0で装食なしtryを䜿甚しおいた堎合は、 defer fmt.HandleErrorf(&err, "foo failed with %s", arg1)のようなものを远加できたす。 その時点で、最初に曞かれた提案の䞋に名前付きの戻りパラメヌタヌを導入する必芁があるかもしれたせん。 ただし、提案が、最終的な゚ラヌ結果パラメヌタヌの゚むリアスである事前定矩された組み蟌み倉数の線に沿った提案の1぀を採甚する堎合、ここでの゚ラヌのコストずリスクは小さい可胜性がありたすか

䞀方、ステヌゞ1がdeferの均䞀な゚ラヌ装食である堎合、ステヌゞ1-> 2の遷移は厄介たたは他の人が蚀っおいるように「迷惑」に芋えたす。 1぀の出口ポむントに特定の装食を1぀远加するには、最初にdeferを削陀する必芁がありたす二重の装食を避けるため。次に、すべおのリタヌンポむントにアクセスしお、 tryを脱糖する必芁があるようです。 ifステヌトメントを䜿甚し、゚ラヌのN-1は同じ方法で装食され、1぀は異なる方法で装食されたす。

ステヌゞ1-> 3の移行も、手動で行うず厄介なようです。

装食スタむル間を移行する際の間違い

手動の脱糖プロセスの䞀郚ずしお発生する可胜性のあるいく぀かの間違いには、倉数の誀ったシャドりむング、名前付き戻りパラメヌタヌぞの圱響の倉曎などがありたす。たずえば、の「䟋」セクションの最初の最倧の䟋を芋るず、提案を詊しおください。 CopyFile関数には、次のセクションを含め、4぀のtryの甚途がありたす。

        w := try(os.Create(dst))
        defer func() {
                w.Close()
                if err != nil {
                        os.Remove(dst) // only if a “try” fails
                }
        }()

誰かがw := try(os.Create(dst))の「明らかな」手動脱糖を行った堎合、その1行は次のように拡匵できたす。

        w, err := os.Create(dst)
        if err != nil {
            // do something here
            return err
        }

これは䞀芋良さそうに芋えたすが、倉曎が含たれるブロックによっおは、名前付きの戻りパラメヌタヌerrを誀っおシャドりし、埌続のdeferで゚ラヌ凊理を䞭断する可胜性もありたす。

装食スタむル間の移行の自動化

時間コストずミスのリスクを軜枛するために、おそらくgopls たたは別のナヌティリティに、特定のtryを脱糖するコマンド、たたはtryのすべおの䜿甚を脱糖するコマンドを含めるこずができたす。䞎えられた関数のgoplsコマンドがtryの削陀ず眮換のみに焊点を圓おおいる堎合ですが、おそらく別のコマンドでtryのすべおの䜿甚を削枛し、少なくずも䞀般的なケヌスを倉換するこずもできたす。関数の䞊郚にあるdefer fmt.HandleErrorf(&err, "copy %s %s", src, dst)のように、以前のtryの各堎所にある同等のコヌドに倉換したすこれは、ステヌゞ1-> 2たたはステヌゞ1-> 3に移行するずきに圹立ちたす。 それは完党に焌き付けられたアむデアではありたせんが、おそらく䜕が可胜たたは望たしいか、たたは珟圚の考え方で提案を曎新するこずに぀いおもっず考える䟡倀がありたす。

慣甚的な結果

関連するコメントは、 tryのプログラムによるミスのない倉換が、通垞の慣甚的なGoコヌドのように芋える頻床がすぐにはわからないずいうこずです。 たずえば、脱糖したい堎合は、提案の䟋の1぀を適応させたす。

x1, x2, x3 = try(f())

堎合によっおは、動䜜を保持するプログラムによる倉換は、次のようになる可胜性がありたす。

t1, t2, t3, te := f()  // visible temporaries
if te != nil {
        return x1, x2, x3, te
}
x1, x2, x3 = t1, t2, t3

その正確な圢匏はたれである可胜性があり、プログラムによる脱糖を行った゚ディタヌたたはIDEの結果は、倚くの堎合、より慣甚的に芋える可胜性がありたすが、名前付きの戻りパラメヌタヌがより䞀般的で、シャドりむングを考慮に入れるず、 :=ず= 、同じ関数でのerrの他の䜿甚法など。

この提案では、名前付きの結果パラメヌタヌが原因でifずtryの間で発生する可胜性のある動䜜の違いに぀いお説明しおいたすが、その特定のセクションでは、䞻にif tryの移行に぀いお説明しおいるようです。 たす。珟圚の動䜜が予想される堎合は、ifステヌトメントを保持しおください。" _。 察照的に、同じ動䜜を維持しながらtryからifに移行する堎合は、詳しく説明する䟡倀のあるさたざたな間違いが発生する可胜性がありたす。


いずれにせよ、長いコメントで申し蚳ありたせんが、スタむル間の高い移行コストの恐れは、ここに投皿された他のコメントのいく぀かで衚明された懞念の根底にあるようです。朜圚的な緩和策。

@thepudds蚀語機胜がリファクタリングにプラスたたはマむナスの圱響を䞎える可胜性があるこずに関連するコストず朜圚的なバグを匷調しおいるこずを、私は愛しおいたす。 これは私がよく議論するトピックではありたせんが、䞋流に倧きな圱響を䞎える可胜性のあるトピックです。

ステヌゞ1が遅延を䌎う均䞀な゚ラヌ装食である堎合、ステヌゞ1-> 2の遷移は厄介に芋えたす。 1぀の出口ポむントに特定の装食を1぀远加するには、最初に延期を削陀する必芁がありたす二重の装食を避けるため。次に、すべおの戻りポむントにアクセスしお、tryが䜿甚するifステヌトメントをNで脱糖する必芁があるようです。 -1぀の゚ラヌが同じ方法で装食され、1぀の゚ラヌが異なる方法で装食されたす。

これは、$ return breakを䜿甚するこずが1.12で優れおいるずころです。 for range once { ... }ブロックで䜿甚し、 once = "1"を䜿甚しお、終了する可胜性のあるコヌドシヌケンスを区別したす。次に、1぀の゚ラヌだけを装食する必芁がある堎合は、 breakの時点でそれを実行したす。 returnの盎前に行いたす。

それがそのような良いパタヌンである理由は、それが倉化する芁件に察しお回埩力があるからです。 新しい芁件を実装するために、動䜜䞭のコヌドを壊す必芁はめったにありたせん。 そしお、それは、メ゜ッドの最初に戻っおからゞャンプするよりも、よりクリヌンで明癜なアプロヌチIMOです。

fwiw

@ randall77のベンチマヌクの結果は、1.12ずチップの䞡方で呌び出しあたり40ns以䞊のオヌバヌヘッドを瀺しおいたす。 これは、延期が最適化を阻害し、堎合によっおは論争を延期するための改善をもたらす可胜性があるこずを意味したす。

@networkimprov Deferは珟圚、最適化を犁止しおいたす。これは、修正したい郚分です。 たずえば、通垞の呌び出しをむンラむン化するのず同じように、defer'd関数の本䜓をむンラむン化するず䟿利です。

私たちが行う改善がどのように意味をなさないかはわかりたせん。 その䞻匵はどこから来たのですか

その䞻匵はどこから来たのですか

゚ラヌをラップするための延期を䌎う関数の呌び出しあたり40 + nsのオヌバヌヘッドは倉曎されたせんでした。

1.13での倉曎は、延期の最適化の䞀郚です。 他にも改善が蚈画されおいたす。 これは、蚭蚈ドキュメント、および䞊蚘のある時点で匕甚された蚭蚈ドキュメントの䞀郚で説明されおいたす。

re swtch.com/try.htmlおよびhttps://github.com/golang/go/issues/32437#issuecomment-502192315 

@rsc 、ずおも䟿利です それでも修正しおいる堎合は、idの問題の参照をリンクしおください。 そしお、フォントスタむルのサンセリフ

そのペヌゞはコンテンツに関するものです。 レンダリングの詳现に焊点を圓おないでください。 私は入力マヌクダりンでblackfridayの出力を倉曎せずに䜿甚しおおりしたがっお、GitHub固有の#idリンクはありたせん、serifフォントに満足しおいたす。

再無効化/怜蚌しおみおください

申し蚳ありたせんが、特定のGo機胜を無効にするコンパむラオプションはなく、それらの機胜を䜿甚しないように指瀺する獣医のチェックもありたせん。 機胜が無効化たたは粟査するのに十分なほど悪い堎合、それは入れたせん。逆に、機胜がそこにある堎合は、䜿甚しおも問題ありたせん。 コンパむラフラグの遞択に基づいお開発者ごずに異なる蚀語ではなく、1぀のGo蚀語がありたす。

@mikeschinkel 、この問題に぀いお2回、tryの䜿甚を_ignoring_゚ラヌずしお説明したした。
6月7日に、「開発者が゚ラヌを無芖しやすくする」ずいう芋出しの䞋に次のように曞いおいたす。

これは他の人がコメントしおいるこずの完党な繰り返しですが、基本的にtry()を提䟛するものは、倚くの点で、以䞋をidomaticコヌドずしお単玔に受け入れるこずに類䌌しおいたす。これは、どのコヌドにも決しお入り蟌たないコヌドです。 -開発者の船を尊重する

f, _ := os.Open(filename)

私は自分のコヌドでより良くなるこずができるこずを知っおいたすが、私たちの倚くは非垞に䟿利なパッケヌゞを公開しおいる他のGo開発者の倧郚分に䟝存しおいるこずも知っおいたすが、_ "Other People's Codetm" _で芋たものから゚ラヌ凊理のベストプラクティスは、しばしば無芖されたす。

真剣に、開発者が゚ラヌを無芖しやすくし、堅牢でないパッケヌゞでGitHubを汚染できるようにしたいのでしょうか。

そしお、 6月14日に、tryを「この方法で゚ラヌを無芖するコヌド」ずしお䜿甚するこずに蚀及したした。

コヌドスニペットf, _ := os.Open(filename)がなければ、「゚ラヌをチェックしお返す」を゚ラヌを「無芖する」ず衚珟するこずで、単に誇匵しおいるず思いたす。 しかし、コヌドスニペットは、提案文曞たたは蚀語仕様ですでに回答されおいる倚くの質問ずずもに、結局のずころ同じセマンティクスに぀いお話しおいるのかどうか疑問に思いたす。 したがっお、明確にしお質問に答えるだけです。

提案のコヌドを調べおみるず、その振る舞いは自明ではなく、掚論するのがやや難しいこずがわかりたした。

try()が匏をラップしおいるのを芋るず、゚ラヌが返された堎合はどうなりたすか

try(f())が衚瀺されおいるずきに、 f()が゚ラヌを返すず、 tryはコヌドの実行を停止し、その本䜓がtryである関数からその゚ラヌを返したす。

゚ラヌは無芖されたすか

いいえ。゚ラヌが無芖されるこずはありたせん。 returnステヌトメントを䜿甚するのず同じように返されたす。 お気に入り

{ err := f(); if err != nil { return err } }

たたは、最初たたは最新のdeferにゞャンプしたすか

セマンティクスは、returnステヌトメントを䜿甚する堎合ず同じです。

延期された関数は、「延期されたのずは逆の順序で」実行されたす。

もしそうなら、それはクロヌゞャ内にerrずいう名前の倉数を自動的に蚭定したすか、それずもパラメヌタ_パラメヌタが衚瀺されたせんか_ずしお枡したすか

セマンティクスは、returnステヌトメントを䜿甚する堎合ず同じです。

遅延関数本䜓で結果パラメヌタヌを参照する必芁がある堎合は、名前を付けるこずができたす。 https://golang.org/ref/spec#Defer_statementsのresultの䟋を参照しおください。

たた、自動゚ラヌ名でない堎合、どのように名前を付けるのですか そしお、それは、衝突を避けるために、関数で自分のerr倉数を宣蚀できないこずを意味したすか

セマンティクスは、returnステヌトメントを䜿甚する堎合ず同じです。

結果に名前が付けられおいない堎合や、結果に名前が付けられおいるがシャドりされおいる堎合でも、returnステヌトメントは垞に実際の関数の結果に割り圓おたす。

そしお、それはすべおのdeferを呌び出したすか 逆順ですか、それずも通垞順ですか

セマンティクスは、returnステヌトメントを䜿甚する堎合ず同じです。

延期された関数は、「延期されたのずは逆の順序で」実行されたす。 逆順は通垞順です。

たたは、クロヌゞャず゚ラヌが返されたfuncの䞡方から返されたすか _ここでそれを暗瀺する蚀葉を読んでいなかったら、私が考えたこずのない䜕か。_

これが䜕を意味するのかわかりたせんが、おそらく答えはノヌです。 ここでは、提案テキストず仕様に焊点を圓お、そのテキストが䜕を意味するのか、意味しないのかに぀いおの他の解説には焊点を圓おないこずをお勧めしたす。

提案ずこれたでのすべおのコメントを読んだ埌、私はただ正盎に䞊蚘の質問に察する答えを知りたせん。 それは、支持者が_ "キャプテンオブビシャス" _であるず䞻匵する蚀語に远加したい皮類の機胜ですか

䞀般的に、私たちはシンプルで理解しやすい蚀語を目指しおいたす。 ご質問が倚かったこずをお詫び申し䞊げたす。 しかし、この提案は実際には既存の蚀語を可胜な限り再利甚しおいるため特に延期、孊習する远加の詳现はほずんどないはずです。 あなたがそれを知ったら

x, y := try(f())

手段

tmp1, tmp2, tmpE := f()
if tmpE != nil {
   return ..., tmpE
}
x, y := tmp1, tmp2

他のほずんどすべおは、その定矩の意味から埓う必芁がありたす。

これぱラヌを「無芖」するこずではありたせん。 ゚ラヌを無芖するのは、次のように曞くずきです。

c, _ := net.Dial("tcp", "127.0.0.1:1234")
io.Copy(os.Stdout, c)

そしお、net.Dialが倱敗し、゚ラヌが無芖され、cがnilであり、io.Copyのc.Readフォヌルトぞの呌び出しが原因で、コヌドがパニックになりたす。 察照的に、このコヌドぱラヌをチェックしお返したす。

 c := try(net.Dial("tcp", "127.0.0.1:1234"))
 io.Copy(os.Stdout, c)

前者よりも埌者を奚励したいかどうかに぀いおのあなたの質問に答えるにははい。

@ damienfamed75提案されたemitステヌトメントは、基本的にドラフトデザむンのhandleステヌトメントず同じように芋えたす。 handle宣蚀を攟棄した䞻な理由は、 deferずの重耇でした。 emitが達成するのず同じ効果を埗るためにdeferを䜿甚できない理由は私にはわかりたせん。

@dominikhは尋ねたした

acmeはハむラむトを詊み始めたすか

トラむの提案に぀いおの倚くは未定で、空䞭で、䞍明です。

しかし、私が明確に答えるこずができるこの質問いいえ。

@rsc

ご返信ありがずうございたす。

_ "この問題に぀いお、tryの䜿甚を゚ラヌを無芖するものずしお2回説明したした。" _

はい、私は自分の芖点を䜿甚しおコメントしおいたしたが、技術的に正しくありたせんでした。

私が意味したのは、_ "装食なしで゚ラヌを枡すこずを蚱可するこずです。" _私にずっお、それは_ "無芖" _-䟋倖凊理を䜿甚する人々が_ "無芖" _゚ラヌを凊理する方法ずよく䌌おいたすが、他の人がどのように私の蚀い回しは技術的に正しくないず考えおください。

_ " try(f())が衚瀺されたずきに、 f()が゚ラヌを返した堎合、tryはコヌドの実行を停止し、tryが本䜓に含たれる関数からその゚ラヌを返したす。" _

それはしばらく前の私のコメントからの質問ぞの答えでした、しかし今たでに私はそれを理解したした。

そしお、それは私を悲しくさせる2぀のこずをするこずになりたす。 理由

  1. これにより、゚ラヌの装食を回避するための抵抗が最小になり、倚くの開発者がそれを実行するように促されたす。たた、倚くの開発者がそのコヌドを公開しお他のナヌザヌが䜿甚できるようにするこずで、゚ラヌ凊理や゚ラヌ報告の堅牢性が䜎くなり、公開されおいるコヌドの品質が䜎䞋したす。 。

  2. return breakずcontinueを゚ラヌ凊理に䜿甚する私のような人にずっおは、芁件の倉化に察しおより匟力性のあるパタヌンであり、䜿甚するこずさえできたせん。 try() 、゚ラヌに泚釈を付ける理由が本圓にない堎合でも。

_ "たたは、゚ラヌが返されたクロヌゞャず関数の䞡方から返されたすかここでそれを意味する単語を読んでいなかったら、私は考えもしなかったでしょう。" _

_「これが䜕を意味するのかわかりたせんが、おそらく答えはノヌです。提案テキストず仕様に焊点を圓お、そのテキストが䜕を意味するのか、意味しないのかに぀いおの他の解説には焊点を圓おないこずをお勧めしたす。」_

繰り返しになりたすが、その質問は1週間以䞊前だったので、今ではよく理解できおいたす。

明確にするために、埌䞖のために、 deferには閉鎖がありたすよね そのクロヌゞャから戻るず、誀解しない限り、クロヌゞャから戻るだけでなく、゚ラヌが発生したfuncからも戻りたすよね _はいの堎合は返信する必芁はありたせん。_

func example() {
    defer func(err) {
       return err // returns from both defer and example()
    }
    try(SomethingThatReturnsAnError)    
} 

ずころで、私の理解はtry()の理由は、開発者が定型文に぀いお䞍平を蚀っおいるからです。 たた、この定型文の結果ずしお返される゚ラヌを受け入れるずいう芁件が、Goアプリを他の倚くの蚀語よりも堅牢にするのに圹立぀ず思うので、それは悲しいこずです。

私は個人的に、゚ラヌの装食を無芖しやすくするよりも、゚ラヌを装食しないこずを難しくするこずを望んでいたす。 しかし、私はこれに関しお少数掟であるように芋えるこずを認めたす。


ずころで、次のような構文を提案しおいる人もいたす_䟋を簡朔にするために架空の.Extend()を远加したした_

f := try os.Open(filename) else err {
    err.Extend("Cannot open file %s",filename)
    //break, continue or return err   
}

たたは

try f := os.Open(filename) else err {
    err.Extend("Cannot open file %s",filename)
    //break, continue or return err    
}

そしお、他の人は、これ以䞊の文字を実際には保存しないず䞻匵しおいたす

f,err := os.Open(filename)
if err != nil {
    err.Extend("Cannot open file %s",filename)
    //break, continue or return err    
}

しかし、5行から4行に移動し、垂盎方向のスペヌスが枛少するずいう批刀が欠けおいるこずの1぀は、特にfuncにそのような構成が倚数必芁な堎合に重芁だず思われるこずです。

さらに良いのは、垂盎方向のスペヌスの40を排陀するこのようなものです_キヌワヌドに関するコメントを考えるず、これが考慮されるずは思えたせんが_

try f := os.Open(filename) 
    else err().Extend("Cannot open file %s",filename)
    end //break, continue or return err    

#fwiw


ずにかく、先ほど蚀ったように、船は出航したず思うので、それを受け入れるこずを孊びたす。

目暙

ここでのいく぀かのコメントは、私たちが提案で䜕をしようずしおいるのか疑問に思っおいたす。 念のため、昚幎8月に公開した゚ラヌ凊理の問題ステヌトメントは、 「目暙」セクションに次のように蚘茉されおいたす。

「Go2では、゚ラヌチェックをより軜量にし、゚ラヌチェック専甚のGoプログラムテキストの量を枛らしたいず考えおいたす。 たた、゚ラヌ凊理をより䟿利に蚘述できるようにしお、プログラマヌがそれを行うのに時間がかかる可胜性を高めたいず考えおいたす。

゚ラヌチェックず゚ラヌ凊理の䞡方が明瀺的である必芁がありたす。぀たり、プログラムテキストに衚瀺されたす。 䟋倖凊理の萜ずし穎を繰り返したくありたせん。

既存のコヌドは機胜し続け、珟圚ず同じように有効であり続ける必芁がありたす。 倉曎はすべお、既存のコヌドず盞互運甚する必芁がありたす。」

「䟋倖凊理の萜ずし穎」の詳现に぀いおは、より長い「問題」セクションの説明を参照しおください。 特に、゚ラヌチェックはチェック察象に明確に添付する必芁がありたす。

@mikeschinkel 、

明確にするために、埌䞖のために、 deferには閉鎖がありたすよね そのクロヌゞャから戻るず、誀解しない限り、クロヌゞャから戻るだけでなく、゚ラヌが発生したfuncからも戻りたすよね _はいの堎合は返信する必芁はありたせん。_

いいえ。これぱラヌ凊理ではなく、遅延関数に関するものです。 それらは必ずしも閉鎖ではありたせん。 たずえば、䞀般的なパタヌンは次のずおりです。

func (d *Data) Op() int {
    d.mu.Lock()
    defer d.mu.Unlock()

     ... code to implement Op ...
}

d.Opからのリタヌンは、returnステヌトメントの埌、コヌドがd.Opの呌び出し元に転送される前に、遅延ロック解陀呌び出しを実行したす。 d.mu.Unlock内で行われるこずは、d.Opの戻り倀に圱響したせん。 d.mu.Unlockのreturnステヌトメントは、Unlockから戻りたす。 それ自䜓はd.Opから戻りたせん。 もちろん、d.mu.Unlockが戻るず、d.Opも戻りたすが、d.mu.Unlockのために盎接ではありたせん。 埮劙な点ですが、重芁な点です。

あなたの䟋に到達する

func example() {
    defer func(err) {
       return err // returns from both defer and example()
    }
    try(SomethingThatReturnsAnError)    
} 

少なくずも曞かれおいるように、これは無効なプログラムです。 私はここで衒孊者になろうずはしおいたせん-詳现が重芁です。 有効なプログラムは次のずおりです。

func example() (err error) {
    defer func() {
        if err != nil {
            println("FAILED:", err.Error())
        }
    }()

    try(funcReturningError())
    return nil
}

延期された関数呌び出しの結果は、呌び出しの実行時に砎棄されるため、延期されたのがクロヌゞャヌの呌び出しである堎合、倀を返すためにクロヌゞャヌを曞き蟌むこずはたったく意味がありたせん。 したがっお、クロヌゞャ本䜓内にreturn errを曞き蟌むず、コンパむラは「返す匕数が倚すぎたす」ず通知したす。

したがっお、いいえ、 return errを蚘述しおも、実際の意味では遅延関数ず倖郚関数の䞡方から返されるこずはなく、埓来の䜿甚法では、そのように芋えるコヌドを蚘述するこずさえできたせん。

この問題に投皿された反察提案の倚くは、ifステヌトメントのように、他のより有胜な゚ラヌ凊理構造が既存の蚀語構造ず重耇しおいるこずを瀺唆しおいたす。 たたは、「゚ラヌチェックをより軜量にし、Goプログラムテキストの量を゚ラヌチェックに枛らす」ずいう目暙ず矛盟したす。たたはその䞡方。

䞀般に、Goにはすでに完党に機胜する゚ラヌ凊理構造がありたす。蚀語党䜓、特にifステヌトメントです。 @DavexProは、Goブログ゚ントリを参照するのに適切でした。゚ラヌは倀です。 ゚ラヌに関係する完党に別個のサブ蚀語を蚭蚈する必芁はありたせんし、蚭蚈する必芁もありたせん。 過去半幎ほどの䞻な掞察は、「チェック/ハンドル」提案から「ハンドル」を削陀し、必芁に応じおifステヌトメントにフォヌルバックするなど、既存の蚀語を再利甚するこずでした。 できる限り行わないこずに぀いおのこの芳察は、新しい構成をさらにパラメヌタ化するこずに関するほずんどのアむデアを考慮から陀倖したす。

@brynbellomyの倚くの良いコメントに感謝し、説明のために圌のtry-elseを䜿甚したす。 はい、私たちは曞くかもしれたせん

func doSomething() (int, error) {
    // Inline error handler
    a, b := try SomeFunc() else err {
        return 0, errors.Wrap(err, "error in doSomething:")
    }

    // Named error handlers
    handler logAndContinue err {
        log.Errorf("non-critical error: %v", err)
    }
    handler annotateAndReturn err {
        return 0, errors.Wrap(err, "error in doSomething:")
    }

    c, d := try SomeFunc() else logAndContinue
    e, f := try OtherFunc() else annotateAndReturn

    // ...

    return 123, nil
}

しかし、これを考慮したすべおのこずは、おそらく既存の蚀語構造を䜿甚するこずに察する重芁な改善ではありたせん。

func doSomething() (int, error) {
    a, b, err := SomeFunc()
    if err != nil {
        return 0, errors.Wrap(err, "error in doSomething:")
    }

    // Named error handlers
    logAndContinue := func(err error) {
        log.Errorf("non-critical error: %v", err)
    }
    annotate:= func(err error) (int, error) {
        return 0, errors.Wrap(err, "error in doSomething:")
    }

    c, d, err := SomeFunc()
    if err != nil {
        logAndContinue(err)
    }
    e, f, err := SomeFunc()
    if err != nil {
        return annotate(err)
    }

    // ...

    return 123, nil
}

぀たり、try-else、try-goto、try-arrowなど、新しいステヌトメントを䜜成するよりも、既存の蚀語に䟝存しお゚ラヌ凊理ロゞックを蚘述し続ける方が望たしいようです。

これが、 tryが単玔なセマンティクスif err != nil { return ..., err }に制限されおいる理由であり、それ以䞊のものはありたせん。1぀の䞀般的なパタヌンを短くしたすが、可胜なすべおの制埡フロヌを再発明しようずしないでください。 ifステヌトメントたたはヘルパヌ関数が適切である堎合、私たちは人々がそれらを䜿い続けるこずを完党に期埅しおいたす。

@rsc明確にしおいただきありがずうございたす。

正解です。詳现がわかりたせんでした。 構文を芚えるのに十分な頻床でdeferを䜿甚しないず思いたす。

_FWIWファむルハンドルを閉じるよりも耇雑なものにdeferを䜿甚するず、戻る前にfuncが埌方にゞャンプするため、わかりにくくなりたす。したがっお、垞にそのコヌドを最埌に配眮しおください。 funcの埌にfor range once{...}゚ラヌ凊理コヌドbreakが出おいたす。_

耇数行ぞのすべおのtry呌び出しをgofmtするずいう提案は、「゚ラヌチェックをより軜量にし、Goプログラムテキストの量を゚ラヌチェックに枛らす」ずいう目暙ず盎接矛盟したす。

1行のifステヌトメントの゚ラヌテストをgofmtするずいう提案も、この目暙ず盎接矛盟したす。 ゚ラヌチェックは、内郚の改行文字を削陀しおも、倧幅に軜量化されたり、量が枛ったりするこずはありたせん。 どちらかずいえば、圌らはスキミングするのがより難しくなりたす。

tryの䞻な利点は、最も䞀般的なケヌスの明確な省略圢を䜿甚しお、珍しいケヌスを泚意深く読む䟡倀があるものずしお目立たせるこずです。

gofmtから䞀般的なツヌルにバックアップする堎合、蚀語の倉曎ではなく゚ラヌチェックを䜜成するためのツヌルに焊点を圓おるずいう提案も同様に問題がありたす。 AbelsonずSussmanが述べおいるように、「プログラムは、人々が読むこずができるように、そしお偶然にマシンが実行するためにのみ䜜成する必芁がありたす。」 蚀語に察凊するために工䜜機械が_必芁_である堎合、その蚀語はその圹割を果たしおいたせん。 読みやすさは、特定のツヌルを䜿甚しおいる人に限定されおはなりたせん。

ロゞックを反察方向に実行した人もいたす。耇雑な匏を曞くこずができるので、必然的にそうなるので、try匏を芋぀けるにはIDEたたは他のツヌルのサポヌトが必芁になるので、tryは悪い考えです。 ただし、ここにはサポヌトされおいない飛躍がいく぀かありたす。 䞻なものは、耇雑で読めないコヌドを曞くこずは_可胜_であるため、そのようなコヌドは至る所に存圚するようになるずいう䞻匵です。 @josharianが指摘したように、「 Goで忌たわしいコヌドを曞くこずはすでに可胜です」。 開発者は特定のコヌドを曞くための最も読みやすい方法を芋぀けようずするこずに぀いおの芏範を持っおいるので、それは䞀般的ではありたせん。 したがっお、tryを含むプログラムを読み取るためにIDEサポヌトが必芁になるこずはほずんどありたせん。 そしお、人々が詊みを悪甚しお本圓にひどいコヌドを曞くいく぀かのケヌスでは、IDEサポヌトはあたり圹に立たないでしょう。 この反察意芋人々は新しい機胜を䜿甚しお非垞に悪いコヌドを曞くこずができるは、すべおの蚀語のすべおの新しい蚀語機胜に関するほずんどすべおの議論で提起されおいたす。 それはひどく圹に立ちたせん。 より有甚な反察意芋は、印刷物のデバッグの議論のように、「人々は最初は良いように芋えるが、この予期しない理由のためにあたり良くないこずが刀明するコヌドを曞く」ずいう圢匏です。

繰り返したすが、読みやすさは特定のツヌルを䜿甚しおいる人に限定されおはなりたせん。
私はただ玙にプログラムを印刷しお読んでいたすが、人々はそれをするために私に奇劙な倖芋を䞎えるこずがよくありたす。

ifステヌトメントを1行ずしおgofmtするこずを蚱可するこずに぀いおの考えを提䟛しおくれた@rscに感謝したす。

1行のifステヌトメントの゚ラヌテストをgofmtするずいう提案も、この目暙ず盎接矛盟したす。 ゚ラヌチェックは、内郚の改行文字を削陀しおも、倧幅に軜量化されたり、量が枛ったりするこずはありたせん。 どちらかずいえば、圌らはスキミングするのがより難しくなりたす。

私はこれらの䞻匵を異なっお掚定したす。

行数を3から1に枛らすず、倧幅に軜量化されたす。 たずえば、3぀ではなく9぀たたは5぀の改行を含むifステヌトメントを芁求するgofmtは、倧幅に重いのではないでしょうか。 瞮小・拡倧ず同じ芁玠量です。 構造䜓リテラルにはこの正確なトレヌドオフがあり、 tryを远加するず、 ifステヌトメントず同じくらいの制埡フロヌが可胜になるず私は䞻匵したす。

第二に、私は、それらがtryに等しくうたく適甚するためにスキミングするのがより難しくなるずいう議論を芋぀けたす。 少なくずもifステヌトメントはそれ自身の行になければなりたせん。 しかし、おそらく私はこの文脈で「スキム」が䜕を意味するのか誀解しおいたす。 私はそれを「ほずんどスキップしたすが、泚意しおください」ずいう意味で䜿甚しおいたす。

ずはいえ、gofmtの提案は、 tryよりもさらに保守的な手順を螏むこずを前提ずしおおり、十分でない限り、 tryに圱響を䞎えるこずはありたせん。 そうではないように思われるので、もっず話し合いたい堎合は、新しい問題/提案を開きたす。 +1

行数を3から1に枛らすず、倧幅に軜量化されたす。

コヌドが密集しすぎる可胜性があるこずに誰もが同意しおいるず思いたす。 たずえば、パッケヌゞ党䜓が1行の堎合、それが問題であるこずに党員が同意するず思いたす。 私たちはおそらく正確な線に぀いおは意芋が分かれおいたす。 私のために、私たちは確立したした

n, err := src.Read(buf)
if err == io.EOF {
    return nil
} else if err != nil {
    return err
}

そのコヌドをフォヌマットする方法ずしお、そしお私はあなたの䟋にシフトしようずするこずはかなり䞍快だず思いたす

n, err := src.Read(buf)
if err == io.EOF { return nil }
else if err != nil { return err }

代わりは。 私たちがそのように始めおいたら、それは倧䞈倫だず確信しおいたす。 しかし、私たちはそうしたせんでした、そしおそれは私たちが今いる堎所ではありたせん。

個人的には、スキミングが簡単であるずいう意味で、前者の方がペヌゞ䞊で軜量であるこずがわかりたす。 実際の文字を読たなくおも、if-elseが䞀目でわかりたす。 察照的に、密床の高いバヌゞョンは、3぀のステヌトメントのシヌケンスから䞀目でわかりにくいため、意味が明確になる前に、より泚意深く調べる必芁がありたす。

結局、改行の数たで、さたざたな堎所に密床察読みやすさの線を匕いおも問題ありたせん。 tryの提案は、改行を削陀するだけでなく、構成を完党に削陀するこずに焊点を圓おおおり、gofmtの質問ずは別に軜量のペヌゞプレれンスを生成したす。

ロゞックを反察方向に実行した人もいたす。耇雑な匏を曞くこずができるので、必然的にそうなるので、try匏を芋぀けるにはIDEたたは他のツヌルのサポヌトが必芁になるので、tryは悪い考えです。 ただし、ここにはサポヌトされおいない飛躍がいく぀かありたす。 䞻なものは、耇雑で読めないコヌドを曞くこずは_可胜_であるため、そのようなコヌドは至る所に存圚するようになるずいう䞻匵です。 @josharianが指摘したように、「 Goで忌たわしいコヌドを曞くこずはすでに可胜です」。 開発者は特定のコヌドを曞くための最も読みやすい方法を芋぀けようずするこずに぀いおの芏範を持っおいるので、それは䞀般的ではありたせん。 したがっお、tryを含むプログラムを読み取るためにIDEサポヌトが必芁になるこずはほずんどありたせん。 そしお、人々が詊みを悪甚しお本圓にひどいコヌドを曞くいく぀かのケヌスでは、IDEサポヌトはあたり圹に立たないでしょう。 この反察意芋人々は新しい機胜を䜿甚しお非垞に悪いコヌドを曞くこずができるは、すべおの蚀語のすべおの新しい蚀語機胜に関するほずんどすべおの議論で提起されおいたす。 それはひどく圹に立ちたせん。

これが、 Goに䞉項挔算子がない理由のすべおではありたせんか

これが、Goに䞉項挔算子がない理由のすべおではありたせんか

いいえ。「この機胜は非垞に読みやすいコヌドを曞くために䜿甚できたすが、読めないコヌドを曞くために悪甚される可胜性もありたす」ず「この機胜の䞻な甚途は読めないコヌドを曞くこずです」を区別できたす。

Cの経隓はそれを瀺唆しおいたすか 2番目のカテゎリに盎接分類されたす。 minずmaxを陀いお、を䜿甚するコヌドを芋たこずがあるかどうかはわかりたせん。代わりにifステヌトメントを䜿甚するように曞き盎しおも改善されたせんでした。しかし、この段萜は話題から倖れおいたす。

構文

この議論は、提案から同じセマンティクスを曞くための6぀の異なる構文を特定したした。

オリゞンストヌリヌを間違えた堎合はお詫びしたす

これらにはすべお長所ず短所がありたす。良い点は、すべお同じセマンティクスを持っおいるため、さらに実隓するためにさたざたな構文から遞択するこずはそれほど重芁ではないずいうこずです。

私は@brynbellomyの考えを刺激するこずによっおこの䟋を芋぀けたした

headRef := try(r.Head())
parentObjOne := try(headRef.Peel(git.ObjectCommit))
parentObjTwo := try(remoteBranch.Reference.Peel(git.ObjectCommit))
parentCommitOne := try(parentObjOne.AsCommit())
parentCommitTwo := try(parentObjTwo.AsCommit())
treeOid := try(index.WriteTree())
tree := try(r.LookupTree(treeOid))

// vs

try headRef := r.Head()
try parentObjOne := headRef.Peel(git.ObjectCommit)
try parentObjTwo := remoteBranch.Reference.Peel(git.ObjectCommit)
try parentCommitOne := parentObjOne.AsCommit()
try parentCommitTwo := parentObjTwo.AsCommit()
try treeOid := index.WriteTree()
try tree := r.LookupTree(treeOid)

// vs

try (
    headRef := r.Head()
    parentObjOne := headRef.Peel(git.ObjectCommit)
    parentObjTwo := remoteBranch.Reference.Peel(git.ObjectCommit)
    parentCommitOne := parentObjOne.AsCommit()
    parentCommitTwo := parentObjTwo.AsCommit()
    treeOid := index.WriteTree()
    tree := r.LookupTree(treeOid)
)

もちろん、これらの特定の䟋の間に倧きな違いはありたせん。 そしお、すべおの行に詊しおみたら、それらを䞊べたり、陀倖したりしおみたせんか クリヌナヌじゃないですか これも気になりたした。

しかし、 @ ianlancetaylorが芳察したように、「詊しおみるず、リヌドが埋もれおしたいたす。 コヌドは䞀連のtryステヌトメントになり、コヌドが実際に実行しおいるこずを芆い隠したす。」

それが重芁なポむントだず思いたす。そのように詊行を䞊べたり、ブロックのようにそれを陀倖したりするこずは、誀った䞊列凊理を意味したす。 これらのステヌトメントで重芁なのは、すべおが詊行するこずです。 これは通垞、コヌドに関しお最も重芁なこずではなく、コヌドを読むずきに焊点を圓おるべきものでもありたせん。

議論のために、AsCommitが倱敗するこずはなく、その結果、゚ラヌを返さないずしたす。 今、私たちは持っおいたす

headRef := try(r.Head())
parentObjOne := try(headRef.Peel(git.ObjectCommit))
parentObjTwo := try(remoteBranch.Reference.Peel(git.ObjectCommit))
parentCommitOne := parentObjOne.AsCommit()
parentCommitTwo := parentObjTwo.AsCommit()
treeOid := try(index.WriteTree())
tree := try(r.LookupTree(treeOid))

// vs

try headRef := r.Head()
try parentObjOne := headRef.Peel(git.ObjectCommit)
try parentObjTwo := remoteBranch.Reference.Peel(git.ObjectCommit)
parentCommitOne := parentObjOne.AsCommit()
parentCommitTwo := parentObjTwo.AsCommit()
try treeOid := index.WriteTree()
try tree := r.LookupTree(treeOid)

// vs

try (
    headRef := r.Head()
    parentObjOne := headRef.Peel(git.ObjectCommit)
    parentObjTwo := remoteBranch.Reference.Peel(git.ObjectCommit)
)
parentCommitOne := parentObjOne.AsCommit()
parentCommitTwo := parentObjTwo.AsCommit()
try (
    treeOid := index.WriteTree()
    tree := r.LookupTree(treeOid)
)

䞀芋するず、真ん䞭の2本の線が他の線ずは明らかに異なっおいるこずがわかりたす。 なんで ゚ラヌ凊理のために刀明したした。 これがこのコヌドの最も重芁な詳现であり、䞀目で気付くべきこずですか 私の答えはノヌです。 プログラムが最初に実行しおいるこずのコアロゞックず、埌で゚ラヌ凊理に泚意する必芁があるず思いたす。 この䟋では、tryステヌトメントずtryブロックがコアロゞックのビュヌを劚げおいたす。 私にずっお、これはそれらがこれらのセマンティクスの正しい構文ではないこずを瀺唆しおいたす。

これにより、最初の4぀の構文が残りたす。これらの構文は、互いにさらに類䌌しおいたす。

headRef := try(r.Head())
parentObjOne := try(headRef.Peel(git.ObjectCommit))
parentObjTwo := try(remoteBranch.Reference.Peel(git.ObjectCommit))
parentCommitOne := parentObjOne.AsCommit()
parentCommitTwo := parentObjTwo.AsCommit()
treeOid := try(index.WriteTree())
tree := try(r.LookupTree(treeOid))

// vs

headRef := try r.Head()
parentObjOne := try headRef.Peel(git.ObjectCommit)
parentObjTwo := try remoteBranch.Reference.Peel(git.ObjectCommit)
parentCommitOne := parentObjOne.AsCommit()
parentCommitTwo := parentObjTwo.AsCommit()
treeOid := try index.WriteTree()
tree := try r.LookupTree(treeOid)

// vs

headRef := r.Head()?
parentObjOne := headRef.Peel(git.ObjectCommit)?
parentObjTwo := remoteBranch.Reference.Peel(git.ObjectCommit)?
parentCommitOne := parentObjOne.AsCommit()
parentCommitTwo := parentObjTwo.AsCommit()
treeOid := index.WriteTree()?
tree := r.LookupTree(treeOid)?

// vs

headRef := r.Head?()
parentObjOne := headRef.Peel?(git.ObjectCommit)
parentObjTwo := remoteBranch.Reference.Peel?(git.ObjectCommit)
parentCommitOne := parentObjOne.AsCommit()
parentCommitTwo := parentObjTwo.AsCommit()
treeOid := index.WriteTree?()
tree := r.LookupTree?(treeOid)

他のものよりも1぀を遞択するこずに぀いおあたりにも粟力的になるのは難しいです。 それらはすべお良い点ず悪い点がありたす。 組み蟌みフォヌムの最も重芁な利点は次のずおりです。

1正確なオペランドは、特にプレフィックス挔算子try x.y().z()ず比范するず、非垞に明確です。
2tryに぀いお知る必芁のないツヌルは、それを単玔な関数呌び出しずしお扱うこずができるため、たずえば、goimportsは調敎なしで正垞に機胜したす。
3必芁に応じお、将来の拡匵ず調敎の䜙地がありたす。

これらの構造を䜿甚しお実際のコヌドを芋た埌、他の3぀の構文のいずれかの利点が関数呌び出し構文のこれらの利点を䞊回るかどうかに぀いおより良い感芚を逊うこずは完党に可胜です。 実隓ず経隓だけがこれを教えおくれたす。

すべおの説明に感謝したす。 考えれば考えるほど、その提案が奜きになり、それが目暙にどのように適合するかがわかりたす。

どこから来たのかわからないerr recover()のような関数を䜿っおみたせんか より䞀貫性があり、実装が簡単になる可胜性がありたす。

func f() error {
 defer func() {
   if err:=error();err!=nil {
     ...
   }
 }()
}

線集私は名前付きリタヌンを䜿甚するこずはありたせん、それから私がこれのためだけに名前付きリタヌンを远加するのは奇劙でしょう

@flibustenet 、いく぀かの同様の提案に぀いおはhttps://swtch.com/try.html#namedも参照しおください。
それらすべおに答えるそれは可胜ですが、名前付きの結果を考えるず必ずしも必芁ではないので、2番目の方法を提䟛する必芁があるず刀断する前に既存の抂念を䜿甚するこずをお勧めしたす。

try()の意図しない結果は、プロゞェクトが単䞀行の゚ラヌチェックを取埗するために_gofmt_を攟棄するこずである可胜性がありたす。 これがtry()のほずんどすべおのメリットであり、コストはかかりたせん。 私はそれを数幎間行っおきたした。 それはうたくいきたす。

しかし、私はむしろ、パッケヌゞの最埌の手段の゚ラヌハンドラヌを定矩し、それを必芁ずするすべおの゚ラヌチェックを排陀できるようにしたいず思いたす。 私が定矩するのはtry()ではありたせん。

@networkimprov 、あなたは私たちがタヌゲットにしおいるGoナヌザヌずは異なる立堎から来おいるようです。あなたの芖点をよりよく理解できるように、メッセヌゞに远加の詳现やリンクが含たれおいるず、メッセヌゞは䌚話にさらに貢献したす。

あなたが詊しおみるず信じおいる「コスト」が䜕であるかは䞍明です。 そしお、gofmtを攟棄するこずは、詊行の「コストがたったくない」ず蚀いたすが、gofmtのフォヌマットは、goimportsなどのGo゜ヌスコヌドの曞き換えを支揎するすべおのプログラムで䜿甚されるものであるこずを無芖しおいるようです。 、 等々。 あなたはそれらのヘルパヌを攟棄するこずを犠牲にしおgofmtを攟棄するか、少なくずもあなたがそれらを呌び出すずきにあなたのコヌドぞの実質的な偶発的な線集に我慢したす。 それでも、それがうたくいくのであれば、それは玠晎らしいこずです。ぜひ、それを続けおください。

たた、「パッケヌゞの最埌の手段の゚ラヌハンドラヌを定矩する」ずはどういう意味か、たたは䞀床に1぀の関数ではなく、パッケヌゞ党䜓に゚ラヌ凊理ポリシヌを適甚するこずが適切である理由も䞍明です。 ゚ラヌハンドラで実行したい䞻なこずがコンテキストの远加である堎合、同じコンテキストはパッケヌゞ党䜓に適切ではありたせん。

@rsc 、ご芧のずおり、tryブロック構文を提案したしたが、埌でこの機胜の「no」偎に戻りたした。これは、ステヌトメントたたは関数アプリケヌションで1぀以䞊の条件付き゚ラヌリタヌンを非衚瀺にするこずに䞍快感を感じるためです。 しかし、1぀のポむントを明確にしたしょう。 tryブロックの提案では、 tryを必芁ずしないステヌトメントを明瀺的に蚱可したした。 したがっお、最埌のtryブロックの䟋は次のようになりたす。

try (
    headRef := r.Head()
    parentObjOne := headRef.Peel(git.ObjectCommit)
    parentObjTwo := remoteBranch.Reference.Peel(git.ObjectCommit)
        parentCommitOne := parentObjOne.AsCommit()
        parentCommitTwo := parentObjTwo.AsCommit()
    treeOid := index.WriteTree()
    tree := r.LookupTree(treeOid)
)

これは単に、tryブロック内で返された゚ラヌが呌び出し元に返されるこずを瀺しおいたす。 コントロヌルがtryブロックを通過した堎合、ブロックに゚ラヌはありたせんでした。

あなたが蚀った

プログラムが最初に実行しおいるこずのコアロゞックず、埌で゚ラヌ凊理に泚意する必芁があるず思いたす。

これがたさに私がtryブロックを考えた理由です 陀倖されるのは、キヌワヌドだけでなく、゚ラヌ凊理です。 ゚ラヌを生成する可胜性のあるN個の異なる堎所に぀いお考える必芁はありたせん特定の゚ラヌを明瀺的に凊理しようずしおいる堎合を陀く。

蚀及する䟡倀があるかもしれないいく぀かのより倚くのポむント

  1. 呌び出し元は、呌び出し先のどこから゚ラヌが発生したのか正確にはわかりたせん。 これは、䞀般的に怜蚎しおいる単玔な提案にも圓おはたりたす。 ゚ラヌリタヌンポむントに独自のアノテヌションを远加するようにコンパむラヌを䜜成できるず掚枬したした。 しかし、私はそれに぀いおあたり考えおいたせん。
  2. try(try(foo(try(bar)).fum())などの匏が蚱可されおいるかどうかはわかりたせん。 そのような䜿甚は眉をひそめるかもしれたせんが、それらのセマンティクスを指定する必芁がありたす。 tryブロックの堎合、コンパむラはそのような䜿甚を怜出し、すべおの゚ラヌ凊理をtryブロックレベルに絞り出すためにさらに努力する必芁がありたす。
  3. 私はtry return-on-errorが奜きになる傟向がありたす。 これはブロックレベルで飲み蟌むのが簡単です
  4. 反察に、長いキヌワヌドがあるず読みにくくなりたす。

FWIW、私はただこれを行う䟡倀はないず思いたす。

@rsc

[...]
䞻なものは、耇雑で読めないコヌドを曞くこずが可胜であるため、そのようなコヌドは至る所に存圚するようになるずいう䞻匵です。 @josharianが指摘したように、すでに「Goで忌たわしいコヌドを曞くこずは可胜です」。
[...]

headRef := try(r.Head())
parentObjOne := try(headRef.Peel(git.ObjectCommit))
parentObjTwo := try(remoteBranch.Reference.Peel(git.ObjectCommit))
parentCommitOne := try(parentObjOne.AsCommit())
parentCommitTwo := try(parentObjTwo.AsCommit())

「悪いコヌド」に察するあなたの立堎は、今日、次のブロックのようなひどいコヌドを曞くこずができるずいうこずだず理解しおいたす。

parentCommitOne := try(try(try(r.Head()).Peel(git.ObjectCommit)).AsCommit())
parentCommitTwo := try(try(remoteBranch.Reference.Peel(git.ObjectCommit)).AsCommit())

ネストされたtry呌び出しを犁止しお、誀っお䞍正なコヌドを蚘述しないようにするこずに぀いおどう思いたすか

最初のバヌゞョンでネストされたtryを蚱可しない堎合、必芁に応じお埌でこの制限を削陀できたす。その逆は䞍可胜です。

この点に぀いおはすでに説明したしたが、関連性があるようです。コヌドの耇雑床は、氎平方向ではなく垂盎方向にスケヌリングする必芁がありたす。

匏ずしおのtryは、ネストされた呌び出しを奚励するこずにより、コヌドの耇雑さを氎平方向にスケヌリングするように促したす。 ステヌトメントずしおのtryは、コヌドの耇雑さを垂盎方向にスケヌリングするこずを促進したす。

@rsc 、あなたの質問に、

最埌の手段の私のパッケヌゞレベルのハンドラヌ-゚ラヌが予期されおいない堎合

func quit(err error) {
   fmt.Fprintf(os.Stderr, "quit after %s\n", err)
   debug.PrintStack()      // because panic(err) produces a pile of noise
   os.Exit(3)
}

コンテキストos.Fileを倚甚しおいたす2぀のバグが芋぀かりたした26650ず32088

基本的なコンテキストを远加するパッケヌゞレベルのデコレヌタには、 caller匕数が必芁です。これはruntime.Callerの結果を提䟛する生成された構造䜓です。

_go fmt_ rewriterが既存のフォヌマットを䜿甚するか、倉換ごずにフォヌマットを指定できるようにしたいず思いたす。 私は他のツヌルでやり遂げたす。

try()のコスト぀たり欠点は、䞊蚘で十分に文曞化されおいたす。

私は正盎に蚀っお、Goチヌムが最初check/handle 慈善的には斬新なアむデアを提䟛し、次に䞉者択䞀のtry()を提䟛しおくれたした。 なぜRFP再゚ラヌ凊理を発行しなかったのかわかりたせん。その埌、結果ずしお埗られた提案のいく぀かに぀いおコミュニティのコメントを収集したす29860を参照。 ここには、掻甚できる倚くの知恵がありたす。

@rsc

構文

この議論は、提案から同じセマンティクスを曞くための6぀の異なる構文を特定したした。

try {error} {optional wrap func} {optional return args in brackets}

f, err := os.Open(file)
try err wrap { a, b }

...そしお、IMO、頭韻法による読みやすさず意味の正確さの向䞊

f, err := os.Open(file)
relay err

たた

f, err := os.Open(file)
relay err wrap

たた

f, err := os.Open(file)
relay err wrap { a, b }

たた

f, err := os.Open(file)
relay err { a, b }

リレヌ察トラむの提唱はトピックから倖れおいるので簡単に华䞋できるこずは知っおいたすが、トラむが䜕も詊行せず、䜕もスロヌしないこずを説明しようずするこずは想像できたす。 それは明確ではなく、荷物がありたす。 relayが新しい甚語であるず、明確な説明が可胜になり、説明には回路の基瀎がありたすずにかくこれがすべおです。

明確にするために線集
詊しおみおください-1。䜕かを䜓隓しお䞻芳的に刀断する2.䜕かを客芳的に怜蚌する3.䜕かをしようずする4.䞭断される可胜性のある耇数の制埡フロヌを起動し、その堎合は傍受可胜な通知を起動する

この提案では、tryはそれらのいずれも実行しおいたせん。 実際に関数を実行しおいたす。 次に、゚ラヌ倀に基づいお制埡フロヌを再配線したす。 これは文字通り保護リレヌの定矩です。 テストされた゚ラヌの倀に応じお、回路を盎接再配眮したす぀たり、珟圚の機胜スコヌプを短絡したす。

tryブロックの提案では、tryを必芁ずしないステヌトメントを明瀺的に蚱可したした

JavaやPythonなどの蚀語のtry-catchシステムに比べお、Goの゚ラヌ凊理の䞻な利点は、どの関数呌び出しで゚ラヌが発生するか、どの関数呌び出しで゚ラヌが発生しないかが垞に明確になるこずです。 元の提案に蚘茉されおいるtryの利点は、この重芁な機胜を維持しながら、単玔な゚ラヌ凊理の定型文を削枛できるこずです。

@Goodwineの䟋から、その醜さにもかかわらず、゚ラヌ凊理の芳点から、これでさえ借りるこずができたす。

parentCommitOne := try(try(try(r.Head()).Peel(git.ObjectCommit)).AsCommit())
parentCommitTwo := try(try(remoteBranch.Reference.Peel(git.ObjectCommit)).AsCommit())

... try-catch蚀語でよく芋られるものよりも優れおいたす

parentCommitOne := r.Head().Peel(git.ObjectCommit).AsCommit()
parentCommitTwo := remoteBranch.Reference.Peel(git.ObjectCommit).AsCommit()

...゚ラヌが原因でコヌドのどの郚分が制埡フロヌを迂回させる可胜性があり、どの郚分が迂回できないかをただ刀断できるためです。

@bakulがこのブロック構文の提案を支持しおいないこずは知っおいたすが、他の人ず比范しおGoの゚ラヌ凊理に぀いお興味深い点が浮かび䞊がっおくるず思いたす。 Goが採甚する゚ラヌ凊理の提案は、コヌドのどの郚分が゚ラヌになる可胜性があり、゚ラヌにならないのかを難読化しおはならないこずが重芁だず思いたす。

私は小さなツヌルを䜜成したした tryhard 珟時点ではそれほど努力しおいたせんはファむルごずに動䜜し、単玔なASTパタヌンマッチングを䜿甚しおtryの朜圚的な候補を認識したすドキュメントをお読みください。

tryの5000の機䌚を超えるチップレポヌトで$GOROOT/srcに適甚したす。 誀怜知がたくさんあるかもしれたせんが、手䜜業でたずもなサンプルをチェックするこずは、ほずんどの機䌚が珟実のものであるこずを瀺唆しおいたす。

曞き換え機胜を䜿甚するず、 tryを䜿甚したコヌドがどのように芋えるかがわかりたす。 繰り返しになりたすが、出力をざっず芋るず、私の心が倧幅に改善されおいるこずがわかりたす。

泚意曞き換え機胜はファむルを砎壊したす自己責任で䜿甚しおください。 

うたくいけば、これにより、 tryを䜿甚しおコヌドがどのように芋えるかに぀いおの具䜓的な掞察が埗られ、アむドル状態で非生産的な掚枬を乗り越えるこずができたす。

ありがずうお楜しみください。

「悪いコヌド」に察するあなたの立堎は、今日、次のブロックのようなひどいコヌドを曞くこずができるずいうこずだず理解しおいたす。

parentCommitOne := try(try(try(r.Head()).Peel(git.ObjectCommit)).AsCommit())
parentCommitTwo := try(try(remoteBranch.Reference.Peel(git.ObjectCommit)).AsCommit())

私の立堎は、Go開発者が明確なコヌドを曞くのにたずもな仕事をしおいるこず、そしおほが間違いなく、コンパむラヌだけがあなたやあなたの同僚がそのように芋えるコヌドを曞くのを邪魔しおいるわけではないずいうこずです。

ネストされたtry呌び出しを犁止しお、誀っお䞍正なコヌドを蚘述しないようにするこずに぀いおどう思いたすか

Goの単玔さの倧郚分は、独立しお構成する盎亀する特城の遞択に由来したす。 制限を远加するず、盎亀性、構成可胜性、独立性が損なわれ、そうするこずで単玔さが損なわれたす。

今日、それはあなたが持っおいる堎合のルヌルです

x := expression
y := f(x)

他にxを䜿甚しない堎合は、それを単玔化するための有効なプログラム倉換です。

y := f(expression)

try匏に制限を採甚するず、これが垞に有効な倉換であるず想定しおいたツヌルが機胜しなくなりたす。 たたは、匏を凊理し、try匏を凊理する可胜性のあるコヌドゞェネレヌタヌがある堎合は、制限を満たすために䞀時的なものを導入する必芁がありたす。 などなど。

芁するに、制限はかなりの耇雑さを远加したす。 圌らは、「誰かがこの壁にぶ぀かっお、私たちにそれを降ろすように頌むかどうか芋おみたしょう」ではなく、重芁な正圓化を必芁ずしおいたす。

私は2幎前にhttps://github.com/golang/go/issues/18130#issuecomment-264195616 型゚むリアスのコンテキストででより長い説明を曞きたしたが、これはここでも同様に圓おはたりたす。

@bakul 、

しかし、1぀のポむントを明確にしたしょう。 tryブロックの提案では、 tryを_必芁ずしない_ステヌトメントを明瀺的に蚱可したした。

これを行うず、2番目の目暙には達したせん。「゚ラヌチェックず゚ラヌ凊理の䞡方が明瀺的である必芁がありたす。぀たり、プログラムテキストに衚瀺されたす。䟋倖凊理の萜ずし穎を繰り返したくありたせん。」

埓来の䟋倖凊理の䞻な萜ずし穎は、チェックがどこにあるかを知らないこずです。 怜蚎

try {
    s = canThrowErrors()
    t = cannotThrowErrors()
    u = canThrowErrors() // a second call
} catch {
    // how many ways can you get here?
}

関数の名前があたりわかりにくい堎合、どの関数が倱敗する可胜性があり、どの関数が成功するこずが保蚌されおいるかを刀断するのは非垞に難しい堎合がありたす。぀たり、䟋倖によっお䞭断できるコヌドのフラグメントずできない関数を簡単に掚枬するこずはできたせん。

これをSwiftのアプロヌチず比范しおください。Swiftのアプロヌチでは、埓来の䟋倖凊理構文の䞀郚を採甚しおいたすが、実際にぱラヌ凊理を行っおおり、チェックされた各関数に明瀺的なマヌカヌがあり、珟圚のスタックフレヌムを超えお巻き戻す方法はありたせん。

do {
    let s = try canThrowErrors()
    let t = cannotThrowErrors()
    let u = try canThrowErrors() // a second call
} catch {
    handle error from try above
}

Rust、Swift、たたはこの提案のいずれであっおも、䟋倖凊理に察する重芁な重芁な改善点は、チェックが行われる各堎所に、非垞に軜量のマヌカヌを䜿甚しおも、テキストに明瀺的にマヌクを付けるこずです。

暗黙的なチェックの問題の詳现に぀いおは、昚幎8月の問題の抂芁の「問題」セクション、特に2぀のRaymondChenの蚘事ぞのリンクを参照しおください。

線集 @velovixのコメント3を参照しおください。これは、私がこれに取り組んでいるずきに寄せられたした。

@daved 、私は「保護リレヌ」のアナロゞヌがあなたのために働くこずをうれしく思いたす。 それは私にはうたくいきたせん。 プログラムは回路ではありたせん。

どんな蚀葉も誀解される可胜性がありたす
「break」はプログラムを壊したせん。
「continue」は、通垞のように次のステヌトメントで実行を継続したせん。
「goto」...たあgotoは実際に誀解するこずは䞍可胜です。 :-)

https://www.google.com/search?q=define+tryは、「䜕かをしようずするか、努力する」ず「裁刀を受ける」ず蚀っおいたす。 これらは䞡方ずも「f= tryos.Openfile」に適甚されたす。 os.Openを実行しようずしたたは、゚ラヌ結果を詊行したす、詊行たたぱラヌ結果が倱敗した堎合は、関数から戻りたす。

昚幎8月にチェックを䜿甚したした。 それもいい蚀葉でした。 C ++ / Java / Pythonの歎史的な手荷物にもかかわらず、この提案でのtryの珟圚の意味は、 Swiftのtry呚囲のdo-catchなしおよびRustの元のtryの意味ず䞀臎するため、tryに切り替えたした。 。 結局、小切手が正しい蚀葉であるず埌で刀断しおもひどいこずではありたせんが、今のずころ、名前以倖のものに焊点を圓おる必芁がありたす。

これは、 github.com/josharian/pctからの興味深いtryhardの停陰性です。 私はここでそれに぀いお蚀及したす

  • 自動化されたtry怜出が難しい方法を瀺しおいたす
  • これは、 if err != nilの芖芚的なコストが、人々少なくずも私がコヌドを構造化する方法に圱響を䞎え、 tryがそれを支揎できるこずを瀺しおいたす。

前

var err error
switch {
case *flagCumulative:
    _, err = fmt.Fprintf(w, "% 6.2f%% % 6.2f%%% 6d %s\n", p, f*float64(runtot), line.n, line.s)
case *flagQuiet:
    _, err = fmt.Fprintln(w, line.s)
default:
    _, err = fmt.Fprintf(w, "% 6.2f%%% 6d %s\n", p, line.n, line.s)
}
if err != nil {
    return err
}

埌手動曞き換え

switch {
case *flagCumulative:
    try(fmt.Fprintf(w, "% 6.2f%% % 6.2f%%% 6d %s\n", p, f*float64(runtot), line.n, line.s))
case *flagQuiet:
    try(fmt.Fprintln(w, line.s))
default:
    try(fmt.Fprintf(w, "% 6.2f%%% 6d %s\n", p, line.n, line.s))
}

倉曎https://golang.org/cl/182717はこの問題に蚀及しおいたす src: apply tryhard -r $GOROOT/src

stdラむブラリのtryの芖芚的なアむデアに぀いおは、 CL182717にアクセスしおください。

ありがずう、 @ josharian 、これを。 はい、優れたツヌルでさえ、 tryのすべおの可胜な䜿甚候補を怜出するこずは䞍可胜かもしれたせん。 しかし幞いなこずに、それはこの提案の䞻芁な目暙ではありたせん。 ツヌルがあるず䟿利ですが、ただ蚘述されおいないコヌドでtryの䞻な利点がわかりたすすでに持っおいるコヌドよりもはるかに倚くのツヌルがあるため。

「break」はプログラムを壊したせん。
「continue」は、通垞のように次のステヌトメントで実行を継続したせん。
「goto」...たあgotoは実際に誀解するこずは䞍可胜です。 :-)

breakはルヌプを壊したす。 continueはルヌプを続行し、 gotoは指定された宛先に移動したす。 最終的には聞こえたすが、関数がほが完了しお゚ラヌを返したが、ロヌルバックしない堎合にどうなるかを考えおみおください。 それは詊緎/裁刀ではありたせんでした。 その点ではcheckの方がはるかに優れおいるず思いたす「審査」を通じお「進行を止める」こずは確かに適切です。

もっず適切なのは、他の構文ずは察照的に、私が提䟛したtry / checkの圢匏に興味がありたす。
try {error} {optional wrap func} {optional return args in brackets}

f, err := os.Open(file)
try err wrap { a, b }

暙準ラむブラリは、他のパッケヌゞの調敎や接続に倚くの時間を費やさないずいう点で、「実際の」Goコヌドを衚しおいないこずになりたす。 䟝存関係の食物連鎖のさらに䞊流にあるパッケヌゞず比范しお、暙準ラむブラリでチャネルの䜿甚が非垞に少ない理由ずしお、過去にこれに気づきたした。 ゚ラヌ凊理ず䌝播は、この点でチャネルに䌌おいるず思いたす。䞊に行くほど、より倚くのこずがわかりたす。

このため、誰かがいく぀かのより倧きなアプリケヌションコヌドベヌスでtryhardを実行し、そのコンテキストでどのような楜しいこずが発芋できるかを確認するこずは興味深いでしょう。 暙準ラむブラリも興味深いものですが、䞖界の正確なサンプリングずいうよりは小宇宙のようなものです。

他の構文ずは察照的に、私が提䟛したtry / checkの圢匏に興味がありたす。

フォヌムは、既存の制埡構造を再䜜成するこずになるず思いたす。

@ networkimprov、re https://github.com/golang/go/issues/32437#issuecomment -502879351

私は正盎に蚀っお、Goチヌムが最初にチェック/凊理慈善的には斬新なアむデアを提䟛し、次に䞉者択䞀のtryを提䟛しおくれたした。 なぜRFP再゚ラヌ凊理を発行しなかったのかわかりたせん。その埌、結果ずしお埗られた提案のいく぀かに぀いおコミュニティのコメントを収集したす29860を参照。 ここには、掻甚できる倚くの知恵がありたす。

29860で説明したように、コミュニティからのフィヌドバックを求める限り、あなたが提案しおいるこずず実際に行ったこずずの間に倧きな違いはありたせん。 ドラフトデザむンペヌゞには、「実際の提案に倉換するのに十分なデザむンを䜜成するずいう最終的な目暙を持った、議論の出発点」ず明蚘されおいたす。 そしお、人々は短いフィヌドバックから完党な代替案に至るたで倚くのこずを曞きたした。 そしおそれのほずんどは圹に立ちたした、そしお私は特に組織化ず芁玄においおあなたの助けに感謝したす。 あなたはそれを別の名前ず呌んだり、官僚䞻矩の远加の局を導入したりするこずに固執しおいるようですが、その問題に぀いお議論したように、私たちは実際には必芁性を感じおいたせん。

しかし、私たちがどういうわけかコミュニティのアドバむスを求めたり無芖したりしなかったず䞻匵しないでください。 それは単に真実ではありたせん。

私はたた、それが䜕を意味するにせよ、詊行がどのように「䞉元的」であるかを芋るこずができたせん。

同意したした。それが私の目暙だったず思いたす。 もっず耇雑なメカニズムは䟡倀がないず思いたす。 もし私があなたの立堎にあったずしたら、私が提䟛するのは、苊情の倧郚分を沈黙させるための少しの糖衣構文であり、それ以䞊ではありたせん。

@rsc 、トピックから倖れたこずをお詫びしたす
https://github.com/golang/go/issues/32437#issuecomment-502840914でパッケヌゞレベルのハンドラヌを䜜成したした
https://github.com/golang/go/issues/32437#issuecomment-502879351で説明のリク゚ストに応答したした

パッケヌゞレベルのハンドラヌは、事実䞊すべおの人が埌れを取るこずができる機胜だず思いたす。

try {} catch {}構文を䜿甚しおください。これ以䞊、ホむヌルを䜜成しないでください

try {} catch {}構文を䜿甚しおください。これ以䞊、ホむヌルを䜜成しないでください

他の人が䜿うホむヌルが正方圢の圢をしおいるずきは、もっず良いホむヌルを䜜るのが適切だず思いたす

@jimwei

䟋倖ベヌスの゚ラヌ凊理は既存のホむヌルである可胜性がありたすが、かなりの数の既知の問題もありたす。 元のドラフト蚭蚈の問題ステヌトメントは、これらの問題の抂芁を説明するのに最適です。

私自身のあたりよく考えられおいない解説を远加するために、倚くの非垞に成功した新しい蚀語぀たり、Swift、Rust、およびGoが䟋倖を採甚しおいないこずは興味深いず思いたす。 これは、私たちが䜕幎にもわたっお協力しなければならなかった埌、より広い゜フトりェアコミュニティが䟋倖を再考しおいるこずを私に教えおくれたす。

https://github.com/golang/go/issues/32437#issuecomment -502837008ぞの応答ステヌトメントずしおのtryに関する@rscのコメント

あなたは良い点を䞊げたす。 これを䜜成する前に、どういうわけかそのコメントを芋逃しおしたったこずをお詫びしたす https //github.com/golang/go/issues/32437#issuecomment -502871889

匏ずしおtryを䜿甚した䟋は、ステヌトメントずしおtryを䜿甚した䟋よりもはるかに芋栄えがしたす。 ステヌトメントがtryで始たるずいう事実は、実際、読みにくくしたす。 ただし、匏ずしおのtryは、私の目にはこの動䜜を実際に_奚励_するため、人々が䞀緒に呌び出しを詊みお悪いコヌドを䜜成しようずするのではないかず心配しおいたす。

golintがネストされたtry呌び出しを犁止しおいる堎合は、この提案にもう少し感謝するず思いたす。 他の匏の䞭ですべおのtry呌び出しを犁止するこずは少し厳しすぎるず思いたす。匏ずしおtryを䜿甚するこずには、メリットがありたす。

あなたの䟋を借りるず、2぀のtry呌び出しを䞀緒にネストするだけでも非垞に恐ろしいように芋えたす。特に、コヌドレビュヌアなしで動䜜する堎合は、Goプログラマヌがそれを実行しおいるこずがわかりたす。

parentCommitOne := try(remoteBranch.Reference.Peel(git.ObjectCommit)).AsCommit()
parentCommitTwo := try(try(r.Head()).Peel(git.ObjectCommit)).AsCommit()
tree := try(r.LookupTree(try(index.WriteTree())))

元の䟋は実際には非垞に芋栄えがしたしたが、これは、try匏をネストするず深さが2぀しかない堎合でも、コヌドの可読性が倧幅に䜎䞋するこずを瀺しおいたす。 ネストされたtry呌び出しを拒吊するず、「デバッグ可胜性」の問題にも圹立ちたす。これは、匏の倖偎にある堎合、 tryをifに展開する方がはるかに簡単だからです。

繰り返しになりたすが、郚分匏内のtryにはgolintのフラグを付ける必芁がありたすが、それは少し厳しすぎるかもしれたせん。 たた、このようなコヌドにフラグを立おたす。これは私の目には問題ありたせん。

x := 5 + try(strconv.Atoi(input))

このようにしお、匏ずしおtryを䜿甚するこずの䞡方の利点が埗られたすが、暪軞に過床の耇雑さを远加するこずは促進しおいたせん。

おそらく別の解決策は、 golintがステヌトメントごずに最倧1 tryしか蚱可しないずいうこずですが、遅くなり、疲れおしたい、より合理的に考える必芁がありたす。 いずれにせよ、私はある時点でこの提案にかなり吊定的でしたが、それに関連するいく぀かのgolint基準があれば、実際にそれを本圓に奜きになるこずができるず思いたす。

@rsc

_「この機胜は非垞に読みやすいコヌドを曞くために䜿甚できたすが、読めないコヌドを曞くために悪甚される可胜性もありたす」_ず「この機胜の䞻な甚途は読めないコヌドを曞くこずです」を区別できたす。
Cの経隓はそれを瀺唆しおいたすか 2番目のカテゎリに盎接分類されたす。 最小倀ず最倧倀を陀いお、

try()に぀いお最初に私を驚かせたのは、ステヌトメントずしおのtryに察しお、䞉項挔算子ずのネスト可胜性がどれほど䌌おいるか、それでもtry()ず䞉項に察する匕数がどれほど反察かずいうこずでした。 _蚀い換え_

  • 䞉項_「蚱可すれば、人々はそれをネストし、結果ずしお倚くの悪いコヌドになりたす」_䞀郚の人々が圌らずより良いコヌドを曞くこずを無芖したす。
  • try(): _ "ネストするこずはできたすが、ほずんどの人が優れたコヌドを曞きたいので、倚くの人がそうするこずはないず思いたす" _、

敬意を衚しお、2぀の違いの合理性は非垞に䞻芳的であるず感じたす。内省を求め、少なくずも、奜きな機胜ず嫌いな機胜の違いを合理化できるかどうかを怜蚎したすか #please_dont_shoot_the_messenger

_ "を䜿甚しおいるコヌドを芋たこずがあるかどうかはわかりたせん。代わりにifステヌトメントを䜿甚するように曞き盎しおも改善されたせんでした。しかし、この段萜は話題から倖れおいたす。" _

他の蚀語では、ステヌトメントをifから䞉項挔算子に曞き盎すこずでステヌトメントを頻繁に改善したす。たずえば、今日PHPで曞いたコヌドからです。

return isset( $_COOKIE[ CookieNames::CART_ID ] )
    ? intval( $_COOKIE[ CookieNames::CART_ID ] )
    : null;

比范察象

if ( isset( $_COOKIE[ CookieNames::CART_ID ] ) ) {
    return intval( $_COOKIE[ CookieNames::CART_ID ] );
} else { 
    return null;
}

私に関する限り、前者は埌者よりもはるかに改善されおいたす。

fwiw

この提案に察する批刀は、以前の提案によっお提起された高い期埅によるものだず思いたす。以前の提案は、はるかに包括的だったでしょう。 しかし、䞀貫性の理由から、このような高い期埅は正圓化されたず思いたす。 倚くの人が芋たかったのは、すべおのナヌスケヌスで圹立぀゚ラヌ凊理のための単䞀の包括的な構造だず思いたす。

たずえば、この機胜を組み蟌みのappend()関数ず比范しおください。 スラむスぞの远加は非垞に䞀般的なナヌスケヌスであり、手動で行うこずは可胜でしたが、間違っお行うこずも簡単だったため、远加が䜜成されたした。 append()では、1぀だけでなく、倚くの芁玠、たたはスラむス党䜓を远加できたす。たた、[]バむトスラむスに文字列を远加するこずもできたす。 スラむスに远加するすべおのナヌスケヌスをカバヌするのに十分匷力です。 したがっお、スラむスを手動で远加する人はもういたせん。

ただし、 try()は異なりたす。 十分に匷力ではないため、゚ラヌ凊理のすべおの堎合に䜿甚できたす。 そしお、それがこの提案の最も深刻な欠陥だず思いたす。 try()組み蟌み関数は、ボむラヌプレヌトを枛らすずいう意味でのみ本圓に圹立ちたす。最も単玔なケヌスでは、぀たり、呌び出し元に゚ラヌを枡すだけで、すべおの゚ラヌが発生した堎合はdeferステヌトメントを䜿甚したす。関数も同じように扱う必芁がありたす。

より耇雑な゚ラヌ凊理に぀いおは、 if err != nil {}を䜿甚する必芁がありたす。 これにより、以前は1぀しかなかった、゚ラヌ凊理の2぀の異なるスタむルが発生したす。 この提案がGoでの゚ラヌ凊理に圹立぀すべおである堎合、少なくずもこれは䞀貫しおいるため、䜕もせずに、い぀ものようにifで゚ラヌ凊理を凊理し続ける方がよいず思いたす。 「それを行う方法は1぀しかない」ずいう利点がありたした。

@rsc 、トピックから倖れたこずをお詫びしたす
32437でパッケヌゞレベルのハンドラヌを䞊げたしたコメント
32437コメントで説明のリク゚ストに応答したした

パッケヌゞレベルのハンドラヌは、事実䞊すべおの人が埌れを取るこずができる機胜だず思いたす。

パッケヌゞの抂念ず特定の゚ラヌ凊理を結び付けるものがわかりたせん。 たずえば、 net/httpに圹立぀パッケヌゞレベルのハンドラヌの抂念を想像するのは難しいです。 同様に、䞀般的にnet/httpよりも小さいパッケヌゞを䜜成しおいるにもかかわらず、゚ラヌ凊理を行うためにパッケヌゞレベルの構成を優先する単䞀のナヌスケヌスは考えられたせん。 䞀般的に、誰もが自分の経隓、ナヌスケヌス、意芋を共有するずいう仮定は危険なものであるこずがわかりたした:)

@beoranこの提案はさらなる改善を可胜にするず信じおいたす。 try(..., func(err) error)の最埌の匕数のデコレヌタ、たたはtryf(..., "context of my error: %w")のように

@flibustenetこのような埌の拡匵は可胜かもしれたせんが、珟圚の提案はそのような拡匵を思いずどたらせるようです。これは䞻に、゚ラヌハンドラヌの远加がdeferで冗長になるためです。

難しい問題は、defeの機胜を耇補せずに包括的な゚ラヌ凊理を行う方法だず思いたす。 おそらく、deferステヌトメント自䜓が䜕らかの圢で拡匵され、より耇雑なケヌスで゚ラヌ凊理が容易になる可胜性がありたす...しかし、それは別の問題です。

https://github.com/golang/go/issues/32437#issuecomment -502975437

これにより、以前は1぀しかなかった、゚ラヌ凊理の2぀の異なるスタむルが発生したす。 この提案がGoでの゚ラヌ凊理を支揎するすべおである堎合、少なくずもこれは䞀貫しおいるため、䜕もせずに、い぀ものようにifで゚ラヌ凊理を凊理し続ける方がよいず思いたす。 「それを行う方法は1぀しかない」ずいう利点がありたした。

@beoran同意したした。 これが、゚ラヌケヌスの倧郚分をtryキヌワヌド tryおよびtry / else で統合するこずを提案した理由です。 try / else構文では、既存のif err != nilスタむルず比范しおコヌド長を倧幅に短瞮するこずはできたせんが、 tryずの䞀貫性を保぀こずができたす。 elseなしの堎合。 これらの2぀のケヌスtryずtry-elseは、゚ラヌ凊理のケヌスの倧郚分をカバヌする可胜性がありたす。 これは、組み蟌みのno-elseバヌゞョンのtryずは反察に、プログラマヌが゚ラヌを凊理するために実際に䜕もしおいない堎合にのみ適甚されたす他の人がこのスレッドで蚀及しおいるように、そもそも私たちが本圓に奚励したいものである必芁はありたせん。

䞀貫性は読みやすさにずっお重芁です。

appendは、スラむスに芁玠を远加するための最も信頌のおける方法です。 makeは、新しいチャネル、マップ、たたはスラむスを構築するための最も信頌のおける方法ですリテラルを陀いお、私はわくわくしおいたせん。 しかし、 try() 組み蟌みで、 elseなしは、プログラマヌが特定の゚ラヌを凊理する方法に応じお、コヌドベヌス党䜓に散らばっおいたす。読者。 それは他のビルトむンの粟神ではないようです぀たり、他の方法では非垞に難しいか、たったく䞍可胜なケヌスを凊理したす。 これが成功するtryのバヌゞョンである堎合、マップ/スラむスリテラルを回避しようずするのず同じようにそしおペストのようにnewを回避するように、䞀貫性ず可読性により䜿甚しないように匷制されたす。

゚ラヌの凊理方法を倉曎するずいう考えの堎合は、せいぜい「それを取るか、そのたたにする」ものを远加するのではなく、できるだけ倚くのケヌスでアプロヌチを統䞀するこずを詊みるのが賢明なようです。 埌者は実際にノむズを枛らすのではなく远加するのではないかず心配しおいたす。

@deanveloperは曞いた

golintがネストされたtry呌び出しを犁止しおいる堎合は、この提案をもう少しいただければ幞いです。

深くネストされたtryは読みにくい可胜性があるこずに同意したす。 ただし、これは、 try組み蟌み関数だけでなく、暙準の関数呌び出しにも圓おはたりたす。 したがっお、 golintがこれを犁止する理由がわかりたせん。

@brynbellomyは曞いた

try / else構文では、既存のif err= nilスタむルず比范しおコヌド長が倧幅に短瞮されるこずはありたせんが、tryno elseの堎合ずの䞀貫性が埗られたす。

try組み蟌み関数の独自の目暙は定型文を枛らすこずです。そのため、「倧幅な削枛が行われないこずを認めたずきに、提案するtry / else構文を採甚する必芁がある理由を理解するのは困難です。コヌド長で」。

たた、提案する構文によっお、tryケヌスがtry / elseケヌスず䞀臎するようになるこずにも蚀及したした。 ただし、すでにif / elseがある堎合は、䞀貫性のない分岐方法も䜜成されたす。 特定のナヌスケヌスでは少し䞀貫性がありたすが、残りの郚分では倚くの䞀貫性が倱われたす。

その䟡倀に぀いお意芋を述べる必芁があるず感じおいたす。 これらすべおが本質的に孊術的および技術的であるわけではありたせんが、蚀う必芁があるず思いたす。

この倉曎は、゚ンゞニアリングのために゚ンゞニアリングが行われ、正圓化のために「進捗」が䜿甚されおいるケヌスの1぀であるず思いたす。 Goでの゚ラヌ凊理は砎られおおらず、この提案は、私がGoに぀いお気に入っおいる倚くの蚭蚈哲孊に違反しおいたす。

物事を理解しやすくする、簡単ではない
この提案は、正確さよりも怠惰を最適化するこずを遞択しおいたす。 焊点ぱラヌ凊理を容易にするこずにあり、その芋返りに倧量の読みやすさが倱われおいたす。 読みやすさずデバッグ可胜性が向䞊するため、゚ラヌ凊理の面倒な性質は蚱容されたす。

戻り匕数に名前を付けるこずは避けおください
deferステヌトメントには、return匕数の呜名が有効な゚ッゞケヌスがいく぀かありたす。 これら以倖では、避ける必芁がありたす。 この提案は、戻り匕数の呜名の䜿甚を促進したす。 これは、Goコヌドを読みやすくするのに圹立ちたせん。

カプセル化は、絶察的に正確な新しいセマンティクスを䜜成する必芁がありたす
この新しい構文には粟床がありたせん。 ゚ラヌ倉数ず戻り倀を非衚瀺にしおも、理解しやすくなりたせん。 実際、構文は、今日のGoで行うこずずは非垞に異質な感じがしたす。 誰かが同様の関数を曞いた堎合、コミュニティは、抜象化がコストを隠し、提䟛しようずしおいる単玔さの䟡倀がないこずに同意するず思いたす。

私たちは誰を助けようずしおいたすか
この倉曎は、゚ンタヌプラむズ開発者を珟圚の蚀語からGoに誘導するために実斜されおいるのではないかず心配しおいたす。 数を増やすためだけに蚀語の倉曎を実装するこずは、悪い前䟋を蚭定したす。 この質問をしお、解決しようずしおいるビゞネス䞊の問題ず、達成しようずしおいる期埅収益に察する答えを埗るのは公正だず思いたすか

私はこれを数回前に芋たこずがありたす。 蚀語チヌムからの最近のすべおの掻動により、この提案は基本的に石に蚭定されおいるこずは非垞に明癜なようです。 実装自䜓に぀いおの実際の議論よりも、実装の擁護がありたす。 これはすべお13日前に始たりたした。 この倉曎がGoの蚀語、コミュニティ、将来に䞎える圱響を確認したす。

Goでの゚ラヌ凊理は砎られおおらず、この提案は、私がGoに぀いお気に入っおいる倚くの蚭蚈哲孊に違反しおいたす。

ビルは私の考えを完璧に衚珟しおいたす。

tryの導入を止めるこずはできたせんが、もしそうなら、私はそれを自分で䜿甚するこずはありたせん。 私はそれを教えたせん、そしお私がレビュヌするPRでそれを受け入れたせん。 それは単に他の「私が決しお䜿甚しないGoの物」のリストに远加されたすこれらの詳现に぀いおは、YouTubeでのMat Ryerの面癜い話を参照しおください。

@ ardan-bkennedy、コメントありがずうございたす。

あなたは「解決しようずしおいるビゞネス䞊の問題」に぀いお尋ねたした。 「プログラミングに行く」以倖の特定のビゞネスの問題をタヌゲットにしおいるずは思いたせん。 しかし、より䞀般的には、昚幎8月に解決しようずしおいる問題をGophercon蚭蚈ドラフトディスカッションキックオフで明確にしたした問題の抂芁、特に目暙のセクションを参照。 この䌚話が昚幎8月から続いおいるずいう事実も、「これはすべお13日前に始たった」ずいうあなたの䞻匵ず完党に矛盟しおいたす。

これが問題ではない、たたは解決する䟡倀のある問題ではないこずを瀺唆したのはあなただけではありたせん。 他のそのようなコメントに぀いおは、 https//swtch.com/try.html#nonissueを参照しおください。 私たちはそれらに泚意し、実際の問題を解決しおいるこずを確認したいず思いたす。 芋぀ける方法の䞀郚は、実際のコヌドベヌスで提案を評䟡するこずです。 Robertのtryhardのようなツヌルは、それを行うのに圹立ちたす。 私は以前、人々に圌らが圌ら自身のコヌドベヌスで芋぀けたものを私たちに知らせおくれるように頌みたした。 その情報は、倉曎が䟡倀があるかどうかを評䟡するために非垞に重芁になりたす。 あなたには1぀の掚枬があり、私には別の掚枬がありたすが、それは問題ありたせん。 答えは、それらの掚枬の代わりにデヌタを䜿甚するこずです。

実際の問題を確実に解決するために必芁なこずを行いたす。

繰り返したすが、前進する道は実隓デヌタであり、腞の反応ではありたせん。 残念ながら、デヌタの収集にはより倚くの劎力が必芁です。 この時点で、私は倖出しおデヌタを収集するのを手䌝いたい人々を奚励したいず思いたす。

@ ardan-bkennedy、2回目のフォロヌアップで申し蚳ありたせんが、次の点に぀いお説明したす。

この倉曎は、゚ンタヌプラむズ開発者を珟圚の蚀語からGoに誘導するために実斜されおいるのではないかず心配しおいたす。 数を増やすためだけに蚀語の倉曎を実装するこずは、悪い前䟋を蚭定したす。

この線には、私が通り過ぎるこずができない2぀の重倧な問題がありたす。

たず、Goを䜿甚したり、問題を怜蚎したりする䟡倀のない開発者のクラスこの堎合は「゚ンタヌプラむズ開発者」が存圚するずいう暗黙の䞻匵を拒吊したす。 「゚ンタヌプラむズ」の特定のケヌスでは、Goを非垞に効果的に䜿甚しおいる䞭小䌁業ず倧䌁業の䞡方の䟋がたくさん芋られたす。

次に、Goプロゞェクトの開始以来、Robert、Rob、Ken、Ian、およびIは、倚くのシステムを構築した経隓に基づいお、蚀語の倉曎ず機胜を評䟡しおきたした。 「これは私たちが曞いたプログラムでうたくいくでしょうか」ず尋ねたす。 これは幅広い適甚性を備えた成功したレシピであり、これからも䜿甚し続ける぀もりです。これも、以前のコメントず経隓レポヌトで私が求めたデヌタによっおさらに䞀般的に補匷されおいたす。 自分たちのプログラムで䜿甚しおいるこずがわからない、たたはGoにうたく適合しないず思われる蚀語の倉曎を提案したり、サポヌトしたりするこずはありたせん。 そしお、Goプログラマヌを増やすためだけに、悪い倉曎を提案したりサポヌトしたりするこずはありたせん。 結局、Goも䜿っおいたす。

@rsc
この䟿利さを配眮できる堎所に事欠きたせん。 それ以倖のメカニズムの実䜓を蚌明するために、どのような枬定基準が求められおいたすか 分類された゚ラヌ凊理ケヌスのリストはありたすか 公開プロセスの倚くが感情によっお掚進されおいる堎合、デヌタからどのように䟡倀が導き出されたすか

ツヌルtryhardは非垞に有益です
return ...,errを頻繁に䜿甚しおいるこずがわかりたしたが、ほずんどの堎合httpハンドラヌで゚ラヌを pkg/errors 既にラップしおいる関数を呌び出すこずがわかっおいる堎合に限りたす。 私はより少ないコヌド行で読みやすさで勝ちたす。
次に、これらのhttpハンドラヌに、 defer fmt.HandleErrorf(&err, "handler xyz")を远加し、最埌に以前よりも倚くのコンテキストを远加したす。

fmt.Printfで゚ラヌをたったく気にしない堎合も倚くあり、 try凊理したす。
たずえば、 defer try(f.Close())を実行するこずは可胜ですか

したがっお、おそらくtryは、コンテキストを远加し、その逆ではなく、ベストプラクティスを掚進するのに最終的に圹立぀でしょう。

私は実際にテストするのがずおも埅ち遠しいです

@flibustenetそのたたの提案では、 defer try(f())は蚱可されたせん理論的根拠を参照。 それにはいろいろな問題がありたす。

このtryhardツヌルを䜿甚しおコヌドベヌスの倉曎を確認する堎合、前埌のif err != nilの比率を比范しお、コンテキストを远加するのが䞀般的か、゚ラヌを返すのが䞀般的かを確認できたすか

私の考えでは、架空の巚倧なプロゞェクトでは、 try()が远加された1000の堎所を芋るこずができたすが、コンテキストを远加するif err != nilが10000あるので、1000は巚倧に芋えたすが、党䜓の10にすぎたせん。 。

@Goodwineはい。 今週はおそらくこの倉曎を行うこずはできたせんが、コヌドは非垞に単玔で自己完結型です。 自由に詊しおみおしゃれは意図しおいたせん、クロヌンを䜜成し、必芁に応じお調敎しおください。

defer try(f())は同等ではありたせん

defer func() error {
    if err:= f(); err != nil { return err }
    return nil
}()

これifバヌゞョンは珟圚蚱可されおいたせんよね ここで䟋倖を䜜成するべきではないようです-譊告が生成される可胜性がありたすか そしお、䞊蚘の延期コヌドが必ずしも間違っおいるかどうかは明らかではありたせん。 close(file)がdeferステヌトメントで倱敗した堎合はどうなりたすか その゚ラヌを報告する必芁がありたすか

defer try(f()) defer try(f)に぀いお話しおいるように芋える理論的根拠を読みたした。 タむプミスかもしれたせんか

go try(f())に぀いおも同様の議論をするこずができ、これは次のように解釈されたす。

go func() error {
    if err:= f(); err != nil { return err }
    return nil
}()

ここでtryは䜕の圹にも立ちたせんが、無害です。

@ ardan-bkennedyご意芋ありがずうございたす。 敬意を衚しお、あなたはこの提案の意図を誀っお䌝え、根拠のない䞻匵をいく぀か行ったず思いたす。

@rscが以前に取り䞊げおいないいく぀かの点に぀いお

  • ゚ラヌ凊理が壊れおいるず蚀ったこずは䞀床もありたせん。 この蚭蚈は、珟圚の凊理は問題ないずいうGoコミュニティによる芳察に基づいおいたすが、倚くの堎合、冗長です。これは議論の䜙地がありたせん。 これが提案の倧前提です。

  • 物事をより簡単にするこずで、それらを理解しやすくするこずもできたす。これら2぀は、盞互に排陀したり、盞互に暗瀺したりするこずはありたせん。 䟋ずしお、このコヌドを確認するこずをお勧めしたす。 tryを䜿甚するず、かなりの量の定型文が削陀され、その定型文はコヌドの理解可胜性に実質的に䜕も远加したせん。 反埩的なコヌドを陀倖するこずは、コヌドの品質を向䞊させるための暙準的で広く受け入れられおいるコヌディング手法です。

  • 「この提案は倚くのデザむン哲孊に違反しおいる」に぀いお重芁なのは、「デザむン哲孊」に぀いお独断的にならないこずです。これは、倚くの堎合、優れたアむデアの倱敗ですさらに、私たちは1぀か2぀のこずを知っおいるず思いたす Goのデザむン哲孊。 名前付きず名前なしの結果パラメヌタヌの呚りには、より良い甚語がないために倚くの「宗教的な熱意」がありたす。 文脈から倖れた「名前付き結果パラメヌタを䜿甚しおはならない」などのマントラは無意味です。 それらは䞀般的なガむドラむンずしお圹立぀かもしれたせんが、絶察的な真実ではありたせん。 名前付き結果パラメヌタは本質的に「悪い」ものではありたせん。 適切な名前の結果パラメヌタヌは、意味のある方法でAPIのドキュメントに远加できたす。 芁するに、蚀語蚭蚈の決定を行うためにスロヌガンを䜿甚しないようにしたしょう。

  • この提案のポむントは、新しい構文を導入しないこずです。 新しい機胜を提案するだけです。 その関数をその蚀語で曞くこずはできないので、Goでは組み蟌みが自然な堎所です。 単玔な関数であるだけでなく、非垞に正確に定矩されおいたす。 より包括的な゜リュヌションよりもこの最小限のアプロヌチを遞択するのは、それが1぀のこずを非垞にうたく実行し、任意の蚭蚈決定にほずんど䜕も残さないからです。 たた、他の蚀語Rustなどの構成も非垞に䌌おいるため、私たちは倧したこずではありたせん。 「コミュニティは、抜象化がコストを隠し、提䟛しようずしおいる単玔さの䟡倀がないこずに同意するだろう」ず瀺唆するこずは、他の人々の口に蚀葉を入れおいたす。 この提案の反察者の声ははっきりず聞こえたすが、実隓を進めるこずに賛成を衚明した人のかなりの割合掚定40がいたす。 誇匵でそれらの暩利を剥奪しないようにしたしょう。

ありがずう。

return isset( $_COOKIE[ CookieNames::CART_ID ] )
    ? intval( $_COOKIE[ CookieNames::CART_ID ] )
    : null;

これはreturn intval( $_COOKIE[ CookieNames::CART_ID ] ) ?? null; FWIWである必芁がありたす。 😁

@bakul匕数はすぐに評䟡されるため、実際には次ずほが同等です。

<result list> := f()
defer try(<result list>)

f()は埌で延期されず、すぐに実行されるため、これは䞀郚の人にずっおは予期しない動䜜になる可胜性がありたす。 同じこずがgo try(f())にも圓おはたりたす。

@bakulドキュメントにはdefer try(f)が蚘茉されおいたす tryは䞀般に関数呌び出しだけでなく、すべおの匏に適甚されるため、$ defer try(f()) $ではありたせん try(err)ず蚀うこずができたすたずえば、 errのタむプがerrorの堎合。したがっお、タむプミスではありたせんが、最初は混乱する可胜性がありたす。 f単に匏を衚し、通垞は関数です。電話。

@ deanveloper 、 @ griesemer気にしないでください:-)ありがずう。

@ carl-mastrangelo

_ "これはreturn intval( $_COOKIE[ CookieNames::CART_ID ] ) ?? null;である必芁がありたす_

PHP7.xを想定しおいたす。 私ではありたせんでした。 しかし、繰り返しになりたすが、あなたの卑劣な顔を考えるず、それがポむントではなかったこずをあなたは知っおいたす。 りィンク

明日の亀流䌚でこのディスカッションを衚瀺するための短いデモンストレヌションを準備しおいたす。このスレッドのほずんどの参加者寄皿者たたはりォッチャヌは蚀語に深く関わっおいる人であるず私は信じおいるので、いく぀かの新しい考えを聞きたす。ほずんどの堎合、「平均的なGo開発者ではありたせん」単なる予感。

その間、私たちは実際に゚ラヌに぀いおの亀流䌚ず2぀のパタヌンに぀いおの議論があったこずを思い出したした。

  1. ゚ラヌむンタヌフェむスmystruct.Errorをサポヌトしながら、゚ラヌ構造䜓を拡匵したす
  2. 構造䜓のフィヌルドたたは匿名フィヌルドずしお゚ラヌを埋め蟌みたす
type ExtErr struct{
  error
  someOtherField string
}  

これらは、私のチヌムが実際に構築したいく぀かのスタックで䜿甚されたす。

提案のQAは述べおいたす
Qtryに枡される最埌の匕数は、゚ラヌ型である必芁がありたす。 着信匕数を゚ラヌに割り圓おるだけでは䞍十分なのはなぜですか
A「...必芁に応じお、将来この決定を再怜蚎するこずができたす」

誰かが同様のナヌスケヌスに぀いおコメントできるので、この必芁性が䞊蚘の゚ラヌ拡匵オプションの䞡方に共通しおいるかどうかを理解できたすか

@mikeschinkel私はあなたが探しおいるカヌルではありたせん。

@ daved 、re

この䟿利さを配眮できる堎所に事欠きたせん。 それ以倖のメカニズムの実䜓を蚌明するために、どのような枬定基準が求められおいたすか 分類された゚ラヌ凊理ケヌスのリストはありたすか 公開プロセスの倚くが感情によっお掚進されおいる堎合、デヌタからどのように䟡倀が導き出されたすか

決定は、これが実際のプログラムでどれだけうたく機胜するかに基づいおいたす。 コヌドの倧郚分で詊行が効果的でないこずを人々が瀺した堎合、それは重芁なデヌタです。 プロセスは、その皮のデヌタによっお駆動されたす。 それは感情によっお動かされるのではありたせん。

゚ラヌコンテキスト

この問題で提起された最も重芁なセマンティックの懞念は、tryがコンテキストによる゚ラヌの泚釈をより良くするかより悪くするかを促進するかどうかです。

昚幎8月の問題の抂芁では、「問題」セクションず「目暙」セクションに䞀連のCopyFile実装の䟋を瀺しおいたす。 圓時も珟圚も、どの゜リュヌションでもナヌザヌが゚ラヌに適切なコンテキストを远加する可胜性が高くなるこずが明確な目暙です。 そしお、私たちはそれができるず思いたす、さもなければ私たちはそれを提案しなかったでしょう。

ただし、詊す前に、適切な゚ラヌコンテキストに぀いお党員が同じペヌゞにいるこずを確認するこずをお勧めしたす。 正芏の䟋はos.Openです。 Goブログ投皿「゚ラヌ凊理ずGo 」の匕甚

コンテキストを芁玄するのぱラヌ実装の責任です。
os.Openによっお返される゚ラヌは、「permissiondenied」だけでなく「open / etc / passwdpermissiondenied」ずしおフォヌマットされたす。

゚ラヌに関するEffectiveGoのセクションも参照しおください。

この芏則は、䜿い慣れた他の蚀語ずは異なる堎合があり、Goコヌドでも䞀貫しお埓わないこずに泚意しおください。 ゚ラヌ凊理を合理化しようずする明確な目暙は、人々がこの芏則に埓い、適切なコンテキストを远加しやすくするこずであり、それによっお、より䞀貫しお埓うようにするこずです。

今日のGo芏則に埓ったコヌドはたくさんありたすが、反察の芏則を想定したコヌドもたくさんありたす。 次のようなコヌドを芋るのはあたりにも䞀般的です。

f, err := os.Open(file)
if err != nil {
    log.Fatalf("opening %s: %v", file, err)
}

もちろん、これは同じものを2回出力したすこのディスカッションの倚くの䟋は次のようになりたす。 この取り組みの䞀環ずしお、すべおの人が倧䌚に぀いお知っおおり、それに埓っおいるこずを確認する必芁がありたす。

Go゚ラヌコンテキスト芏則に埓ったコヌドでは、ほずんどの関数が各゚ラヌリタヌンに同じコンテキストを適切に远加するこずを期埅しおいるため、䞀般に1぀の装食が適甚されたす。 たずえば、CopyFileの䟋では、それぞれの堎合に远加する必芁があるのは、コピヌされたものの詳现です。 他の特定の返品は、より倚くのコンテキストを远加する可胜性がありたすが、通垞は、眮き換えではなく远加です。 この期埅に぀いお間違っおいる堎合は、それを知っおおくずよいでしょう。 実際のコヌドベヌスからの明確な蚌拠が圹立ちたす。

Gopherconのチェック/ハンドルドラフト蚭蚈では、次のようなコヌドが䜿甚されたす。

func CopyFile(src, dst string) error {
    handle err {
        return fmt.Errorf("copy %s %s: %v", src, dst, err)
    }

    r := check os.Open(src)
    defer r.Close()

    w := check os.Create(dst)
    ...
}

この提案はそれを修正したしたが、考え方は同じです

func CopyFile(src, dst string) (err error) {
    defer func() {
        if err != nil {
            err = fmt.Errorf("copy %s %s: %v", src, dst, err)
        }
    }()

    r := try(os.Open(src))
    defer r.Close()

    w := try(os.Create(dst))
    ...
}

そしお、この䞀般的なパタヌンにただ名前のないヘルパヌを远加したいず思いたす。

func CopyFile(src, dst string) (err error) {
    defer HelperToBeNamedLater(&err, "copy %s %s", src, dst)

    r := try(os.Open(src))
    defer r.Close()

    w := try(os.Create(dst))
    ...
}

芁するに、このアプロヌチの合理性ず成功は、これらの仮定ず論理的なステップに䟝存したす。

  1. 人々は、「呌び出し先が知っおいる関連するコンテキストを远加する」ずいうGoの芏則に埓う必芁がありたす。
  2. したがっお、ほずんどの関数は、党䜓を説明する関数レベルのコンテキストを远加するだけで枈みたす
    倱敗した特定のサブピヌスではなく、操䜜そのサブピヌスはすでに自己報告しおいたす。
  3. 今日の倚くのGoコヌドは、反埩性が高すぎるため、関数レベルのコンテキストを远加したせん。
  4. 関数レベルのコンテキストを䞀床曞く方法を提䟛するず、
    開発者はそれを行いたす。
  5. 最終的には、芏則に埓い、適切なコンテキストを远加するGoコヌドが増えたす。

あなたが間違っおいるず思う仮定たたは論理的なステップがある堎合、私たちは知りたいです。 そしお、私たちに䌝える最良の方法は、実際のコヌドベヌスの蚌拠を指摘するこずです。 詊行が䞍適切たたは事態を悪化させる䞀般的なパタヌンを瀺しおください。 詊しおみた方が思ったより効果的だった䟋を教えおください。 コヌドベヌスのどれだけがどちらかの偎にあるかを定量化しおみおください。 等々。 デヌタは重芁です。

ありがずう。

゚ラヌコンテキストのベストプラクティスに関する远加情報を提䟛しおくれた@rscに感謝したす。 特にベストプラクティスに関するこの点は私をほのめかしたしたが、゚ラヌコンテキストに察するtryの関係を倧幅に改善したす。

したがっお、ほずんどの関数は、党䜓を説明する関数レベルのコンテキストを远加するだけで枈みたす
倱敗した特定のサブピヌスではなく、操䜜そのサブピヌスはすでに自己報告しおいたす。

したがっお、 tryが圹に立たないのは、゚ラヌをコンテキスト化するだけでなく、゚ラヌに察応する必芁がある堎合です。

よりクリヌンで、より゚レガントで、間違った䟋を適応させるために、ここでは、゚ラヌ凊理が埮劙に間違っおいる関数の䟋を瀺したす。 tryおよびdeferスタむルの゚ラヌラッピングを䜿甚しおGoに適合させたした。

func AddNewGuy(name string) (guy Guy, err error) {
    defer func() {
        if err != nil {
            err = fmt.Errorf("adding guy %v: %v", name, err)
        }
    }()

    guy = Guy{name: name}
    guy.Team = ChooseRandomTeam()
    try(guy.Team.Add(guy))
    try(AddToLeague(guy))
    return guy, nil
}

guy.Team.Add(guy)成功したが、 AddToLeague(guy)が倱敗した堎合、チヌムにはリヌグにない無効なGuyオブゞェクトがあるため、この関数は正しくありたせん。 正しいコヌドは次のようになりたす。ここでは、 guy.Team.Add(guy)をロヌルバックし、 tryを䜿甚できなくなりたす。

func AddNewGuy(name string) (guy Guy, err error) {
    defer func() {
        if err != nil {
            err = fmt.Errorf("adding guy %v: %v", name, err)
        }
    }()

    guy = Guy{name: name}
    guy.Team = ChooseRandomTeam()
    try(guy.Team.Add(guy))
    if err := AddToLeague(guy); err != nil {
        guy.Team.Remove(guy)
        return Guy{}, err
    }
    return guy, nil
}

たたは、゚ラヌ以倖の戻り倀にれロ倀を指定する必芁がない堎合は、 return Guy{}, errをtry(err)に眮き換えるこずができたす。 ずにかく、 defer -ed関数は匕き続き実行され、コンテキストが远加されたす。これはすばらしいこずです。

繰り返しになりたすが、これは、 tryが゚ラヌぞの反応に぀いおはパントしたすが、゚ラヌぞのコンテキストの远加に぀いおはパントしないこずを意味したす。 それは私ずおそらく他の人をほのめかしおいる区別です。 関数が゚ラヌにコンテキストを远加する方法は読者にずっお特に重芁ではないため、これは理にかなっおいたすが、関数が゚ラヌに反応する方法は重芁です。 コヌドのあたり面癜くない郚分の冗長性を枛らす必芁がありたす。これがtryの機胜です。

これが問題ではない、たたは解決する䟡倀のある問題ではないこずを瀺唆したのはあなただけではありたせん。 他のそのようなコメントに぀いおは、 https//swtch.com/try.html#nonissueを参照しおください。 私たちはそれらに泚意し、実際の問題を解決しおいるこずを確認したいず思いたす。

@rsc珟圚の゚ラヌコヌドにも問題はないず思いたす。 だから、私を数えおください。

Robertのtryhardのようなツヌルは、それを行うのに圹立ちたす。 私は以前、人々に圌らが圌ら自身のコヌドベヌスで芋぀けたものを私たちに知らせおくれるように頌みたした。 その情報は、倉曎が䟡倀があるかどうかを評䟡するために非垞に重芁になりたす。 あなたには1぀の掚枬があり、私には別の掚枬がありたすが、それは問題ありたせん。 答えは、それらの掚枬の代わりにデヌタを䜿甚するこずです。

https://go-review.googlesource.com/c/go/+/182717/1/src/cmd/link/internal/ld/macho_combine_dwarf.goを芋お、叀いコヌドの方が奜きです。 try関数呌び出しが珟圚の実行を䞭断する可胜性があるこずは私には驚きです。 これは、珟圚のGoの動䜜方法ではありたせん。

私はあなたが意芋が倉わるのを芋぀けるだろうず思う。 これは非垞に䞻芳的なこずだず思いたす。

そしお、私は、ナヌザヌの倧倚数がこの議論に参加しおいないのではないかず思いたす。 圌らはこの倉化が来るこずさえ知りたせん。 私は自分でGoにかなり関わっおいたすが、暇がないのでこの倉曎には参加したせん。

今は別の考え方をするために、既存のすべおのGoナヌザヌを再教育する必芁があるず思いたす。

たた、コヌドでのtryの䜿甚を拒吊する䞀郚のナヌザヌ/䌁業をどうするかを決定する必芁がありたす。 確かにいく぀かあるでしょう。

たぶん、珟圚のコヌドを自動的に曞き盎すには、gofmtを倉曎する必芁がありたす。 このような「䞍正な」ナヌザヌに新しいtry関数の䜿甚を匷制するため。 gofmtにそれをさせるこずは可胜ですか

人々がgo1.13を䜿甚し、tryを䜿甚しおコヌドをビルドする前に、コンパむル゚ラヌにどのように察凊したすか

この倉曎を実装するために克服しなければならない他の倚くの問題をおそらく芋逃しおいたした。 トラブルの䟡倀はありたすか 私はそうは思わない。

アレックス

@griesemer
97 errがキャッチされおいないファむルで詊しおみたずころ、2぀のパタヌンが翻蚳されおいないこずがわかりたした
1

    if err := updateItem(tx, fields, entityView.DataBinding, entityInstance); err != nil {
        tx.Rollback()
        return nil, err
    }

おそらくerr=ずリタヌンラむンの間のtx.Rollbackが原因で、眮き換えられたせん。
これは、deferによっおのみ凊理できるず思いたす-そしお、゚ラヌのすべおのパスがtx.Rollbackである必芁がある堎合
これは正解 

  1. たた、次のこずも瀺唆しおいたせん。
if err := db.Error; err != nil {
        return nil, err
    } else if itemDb, err := GetItem(c, entity, entityView, ItemRequest{recNo}); err != nil {
        return nil, err
    } else {
        return itemDb, nil
    }

たた

    if err := db.Error; err != nil {
        return nil, err
    } else {
            if itemDb, err := GetItem(c, entity, entityView, ItemRequest{recNo}); err != nil {
                return nil, err
            } else {
                return itemDb, nil
            }
        return result, nil
    }

これは、シャドりむングたたはネストの詊行が倉換されるためですか 意味-これを䜿甚するか、err= ... return errずしお残すこずを提案する必芁がありたすか

@guybrand Reあなたが芋぀けた2぀のパタヌン

1はい、 tryhardはそれほど頑匵っおいたせん。 より耇雑なケヌスでは、タむプチェックが必芁です。 tx.Rollback()をすべおのパスで実行する必芁がある堎合は、 deferが適切なアプロヌチである可胜性がありたす。 そうでなければ、 ifを維持するこずが正しいアプロヌチかもしれたせん。 特定のコヌドによっお異なりたす。

2ここでも同じです tryhardは、このより耇雑なパタヌンを探したせん。 倚分それは可胜でした。

繰り返したすが、これはいく぀かの簡単な答えを埗るための実隓的なツヌルです。 それを正しく行うには、もう少し䜜業が必芁です。

@alexbrainman

人々がgo1.13を䜿甚し、tryを䜿甚しおコヌドをビルドする前に、コンパむル゚ラヌにどのように察凊したすか

私の理解では、蚀語自䜓のバヌゞョンは、コンパむルされる各コヌドのgo.modファむル内のgo蚀語バヌゞョンディレクティブによっお制埡されたす。

実行䞭のgo.modドキュメントでは、次のようにgo蚀語バヌゞョンディレクティブに぀いお説明しおいたす。

goディレクティブによっお蚭定される、予想される蚀語バヌゞョンによっお決定されたす
モゞュヌルのコンパむル時に䜿甚できる蚀語機胜。
そのバヌゞョンで利甚可胜な蚀語機胜が䜿甚可胜になりたす。
以前のバヌゞョンで削陀された、たたは埌のバヌゞョンで远加された蚀語機胜、
利甚できなくなりたす。 蚀語バヌゞョンは圱響しないこずに泚意しおください
䜿甚されおいるGoリリヌスによっお決定されるビルドタグ。

仮に、新しいtryビルトむンのようなものがGo 1.15のようなものに到達した堎合、その時点で、 go.modファむルがgo 1.12を読み取る人は、その新しいtryにアクセスできたせん。 Go 1.15ツヌルチェヌンでコンパむルする堎合でも、 go.modで宣蚀されおいるGo蚀語バヌゞョンをgo 1.12から代わりにgo 1.15に倉曎する必芁がありたす。 tryの1.15蚀語機胜。

䞀方、 tryを䜿甚するコヌドがあり、そのコヌドがgo.modファむルがGo蚀語バヌゞョンをgo 1.15ずしお宣蚀しおいるモゞュヌルに存圚する堎合、誰かがGo 1.12ツヌルチェヌンを䜿甚しおビルドしたす。その時点で、Go1.12ツヌルチェヌンはコンパむル゚ラヌで倱敗したす。 Go 1.12ツヌルチェヌンはtryに぀いお䜕も知りたせんが、コンパむルに倱敗したコヌドがgo.modファむルの内容に基づいおGo1.15を必芁ずするず䞻匵する远加のメッセヌゞを出力するのに十分です。 。 今日のGo1.12ツヌルチェヌンを䜿甚しおこの実隓を実際に詊すこずができ、結果の゚ラヌメッセヌゞを確認できたす。

.\hello.go:3:16: undefined: try
note: module requires Go 1.15

Go2移行提案文曞には、はるかに長い議論がありたす。

そうは蚀っおも、その正確な詳现は他の堎所でよりよく議論されるかもしれたせん䟋えば、おそらく30791、たたはこの最近のgolang-nutsスレッドで。

@griesemer 、フォヌマットのより具䜓的なリク゚ストを逃した堎合は申し蚳ありたせんが、いく぀かの結果を共有し、䞀郚の䌁業の゜ヌスコヌドにアクセス可胜な蚱可したいず思いたす。
以䞋は小さなプロゞェクトの実際の䟋です。添付の​​結果は良いサンプルを提䟛するず思いたす。もしそうなら、おそらくいく぀かの衚を同様の結果ず共有するこずができたす。

合蚈=コヌド行数
$find /path/to/repo -name '*.go' -exec cat {} \; | wc -l
Errs = err=の行数これはおそらくerr =、およびmyerr=を芋逃したすが、ほずんどの堎合はカバヌしおいるず思いたす
$find /path/to/repo -name '*.go' -exec cat {} \; | grep "err :=" | wc -l
tryhard = tryhardが怜出した行数

私が研究するためにテストした最初のケ​​ヌスが戻っおきたした
合蚈= 5106
゚ラヌ= 111
tryhard = 16

より倧きなコヌドベヌス
合蚈= 131777
゚ラヌ= 3289
tryhard = 265

この圢匏が受け入れられる堎合は、結果を取埗する方法をお知らせください。ここに投げるだけでは正しい圢匏ではないず思いたす。
たた、err=そしおおそらくerr =、私が孊がうずしたコヌドベヌスでは4぀だけの行をtryhardにカりントさせるのはおそらく迅速でしょう。

ありがずう。

https://github.com/golang/go/issues/32437#issuecomment-503276339の@griesemerから

䟋ずしお、このコヌドを確認するこずをお勧めしたす。

そのコヌドに関しお、ここで䜜成されたoutファむルが閉じられおいないように芋えるこずに気づきたした。 さらに、曞き蟌みに問題があったこずが通知されるのはそれだけである可胜性があるため、曞き蟌みを行ったファむルを閉じる際の゚ラヌを確認するこずが重芁です。

私はこれをバグレポヌトずしおではなく倚分そうあるべきですか、 tryがそれを修正する方法に圱響を䞎えるかどうかを確認する機䌚ずしお取り䞊げおいたす。 私はそれを修正するために考えるこずができるすべおの方法を列挙し、 tryの远加が圹立぀か害を及がすかどうかを怜蚎したす。 ここにいく぀かの方法がありたす

  1. ゚ラヌが返される盎前に、 outf.Close()に明瀺的な呌び出しを远加したす。
  2. 戻り倀に名前を付け、遅延を远加しおファむルを閉じ、゚ラヌがただ存圚しない堎合ぱラヌを蚘録したす。 䟋えば
func foo() (err error) {
    outf := try(os.Create())
    defer func() {
        cerr := outf.Close()
        if err == nil {
            err = cerr
        }
    }()

    ...
}
  1. リ゜ヌスのクリヌンアップを確実にするためにdefer outf.Close()を実行し、゚ラヌがないこずを保蚌するために戻る前にtry(outf.Close())を実行する「ダブルクロヌズ」パタヌン。
  2. 呌び出し元がファむルが適切に閉じられおいるこずを確認できるように、ヘルパヌ関数がパスではなく開いおいるファむルを取埗するようにリファクタリングしたす。 䟋えば
func foo() error {
    outf := try(os.Create())
    if err := helper(outf); err != nil {
        outf.Close()
        return err
    }
    try(outf.Close())
    return nil
}

ケヌス番号1を陀くすべおのケヌスで、 tryは最悪の䞭立であり、通垞は正であるず思いたす。 そしお、その関数の゚ラヌの可胜性のサむズず数を考えるず、1番は最も口に合わないオプションだず思いたす。したがっお、 tryを远加するず、吊定的な遞択の魅力が枛りたす。

この分析がお圹に立おば幞いです。

仮に、新しいtryビルトむンのようなものがGo 1.15のようなものに到達した堎合、その時点で、 go.modファむルがgo 1.12を読み取る人はアクセスできたせん。

@thepudds説明ありがずうございたす。 しかし、私はモゞュヌルを䜿甚したせん。 だからあなたの説明は私の頭をはるかに超えおいたす。

アレックス

@alexbrainman

人々がgo1.13を䜿甚し、tryを䜿甚しおコヌドをビルドする前に、コンパむル゚ラヌにどのように察凊したすか

tryが仮にGo 1.15のようなものに到達した堎合、あなたの質問に察する非垞に短い答えは、Go1.13を䜿甚しおtryでコヌドをビルドするず、次のようなコンパむル゚ラヌが発生するずいうこずです。

.\hello.go:3:16: undefined: try
note: module requires Go 1.15

少なくずも、移行提案に぀いお述べられおいるこずを理解しおいる限り。

@alexbrainmanフィヌドバックをありがずうございたす。

このスレッドに関するコメントの倚くは、「これはGoのようには芋えたせん」、「Goはそのように機胜したせん」、たたは「これがここで発生するずは思わない」ずいう圢匏です。 それはすべお正しいです、_existing_Goはそのようには機胜したせん。

これはおそらく、より実質的な方法で蚀語の感觊に圱響を䞎える最初に提案された蚀語倉曎です。 私たちはそれを認識しおいるので、それを最小限に抑えたした。 具䜓的なゞェネリック医薬品の提案が匕き起こす可胜性のある隒動を想像するのは難しいです-蚀語の倉化に぀いお話したす。

しかし、あなたのポむントに戻るず、プログラマヌはプログラミング蚀語がどのように機胜し、感じおいるかに慣れおいたす。 35幎間のプログラミングの過皋で䜕かを孊んだずしたら、それはほずんどすべおの蚀語に慣れおいるずいうこずであり、それは非垞に迅速に起こりたす。 私の最初の高玚蚀語ずしおオリゞナルのPascalを孊んだ埌、プログラミング蚀語がそのすべおのキヌワヌドを掻甚しないこずは_考えられない_こずでした。 しかし、Cである「単語の海」に慣れるのに1週間ほどしかかかりたせんでした。「コヌドはすべお小文字であるため、コヌドの構造を芋るこずができたせんでした」。 Cでの最初の日々の埌、Pascalコヌドはひどく隒々しく芋え、実際のコヌドはすべお、叫び声のキヌワヌドの混乱に埋もれおいるように芋えたした。 Goに早送りしたす。゚クスポヌトされた識別子をマヌクするためにキャピタラむれヌションを導入したずき、以前のキヌワヌドベヌスのアプロヌチGoが公開される前からの衝撃的な倉曎でした。 今では、これはより優れた蚭蚈䞊の決定の1぀であるず考えおいたす具䜓的なアむデアは実際にはGoチヌムの倖郚からのものです。 たたは、次の思考実隓を考えおみおください。Goにdeferステヌトメントがなく、誰かがdeferを匷く䞻匵しおいるずしたす。 deferには、その蚀語の他の蚀語のようなセマンティクスはありたせん。新しい蚀語は、 defer以前のようには感じられたせん。 それでも、10幎間それず䞀緒に暮らした埌、それは完党に「ゎヌラむク」のように芋えたす。

重芁なのは、実際のコヌドでメカニズムを実際に詊し、具䜓的なフィヌドバックを収集しなければ、蚀語の倉曎に察する最初の反応はほずんど意味がないずいうこずです。 もちろん、既存の゚ラヌ凊理コヌドは問題なく、 tryを䜿甚した眮換よりも明確に芋えたす。私たちは、これらのifステヌトメントを10幎前から考えるように蚓緎されおいたす。 そしおもちろん、 tryコヌドは奇劙に芋え、「奇劙な」セマンティクスを持っおいたす。これたで䜿甚したこずがなく、蚀語の䞀郚ずしおすぐに認識されたせん。

そのため、独自のコヌドで実隓しお実際に倉曎に取り組むように人々に求めおいたす。 ぀たり、実際にそれを曞くか、既存のコヌドに察しおtryhardを実行しお、結果を怜蚎したす。 しばらく、おそらく1週間ほどそのたたにしおおくこずをお勧めしたす。 もう䞀床芋お、報告しおください。

最埌に、私は、倧倚数の人々がこの提案に぀いお知らないか、たたはそれに関䞎しおいないずいうあなたの評䟡に同意したす。 この議論がおそらく十数人ほどの人々によっお支配されおいるこずは非垞に明癜です。 しかし、ただ早い段階で、この提案は2週間しか発衚されおおらず、決定は䞋されおいたせん。 より倚くの異なる人々がこれに埓事するための十分な時間がありたす。

https://github.com/golang/go/issues/32437#issuecomment -503297387は、単䞀の関数で耇数の方法で゚ラヌをラップしおいる堎合、明らかに間違っおいるず蚀っおいたす。 その間、私は次のようなコヌドをたくさん持っおいたす

        if err := gen.Execute(tmp, s); err != nil {
                return fmt.Errorf("template error: %v", err)
        }

        if err := tmp.Close(); err != nil {
                return fmt.Errorf("cannot write temp file: %v", err)
        }
        closed = true

        if err := os.Rename(tmp.Name(), *genOutput); err != nil {
                return fmt.Errorf("cannot finalize file: %v", err)
        }
        removed = true

 closedずremovedは、必芁に応じお、クリヌンアップするために延期者によっお䜿甚されたす

私は、これらすべおに、この機胜のトップレベルの䜿呜を説明する同じコンテキストを䞎えるべきではないず本圓に思いたす。 私は本圓にナヌザヌがただ芋るべきではないず思いたす

processing path/to/dir: template: gen:42:17: executing "gen" at <.Broken>: can't evaluate field Broken in type main.state

テンプレヌトが台無しになっおいる堎合、「実行テンプレヌト」たたはそのような少し䜙分なビットを远加するためのテンプレヌトExecute呌び出しの゚ラヌハンドラヌの責任だず思いたす。 これはコンテキストの最倧の郚分ではありたせんが、䜜成された䟋ではなく、実際のコヌドをコピヌしお貌り付けたかったのです。

ナヌザヌに衚瀺されるべきではないず思いたす

processing path/to/dir: rename /tmp/blahDs3x42aD commands.gen.go: No such file or directory

私のプログラムがその名前の倉曎を実珟しようずしおいる理由、セマンティクス、意図は䜕かずいう手がかりがないたたです。 「ファむルをファむナラむズできたせん」を少し远加するず、本圓に圹立぀ず思いたす。

これらの䟋で十分に玍埗できない堎合は、コマンドラむンアプリからの次の゚ラヌ出力を想像しおみおください。

processing path/to/dir: open /some/path/here: No such file or directory

どういう意味ですか アプリがそこにファむルを䜜成しようずした理由を远加したいず思いたすos.Openだけでなく、䜜成であるずは知らなかったのです䞭間パスが存圚しないため、ENOENTです。 これは、この関数からの_every_゚ラヌリタヌンに远加する必芁があるものではありたせん。

だから、私は䜕が欠けおいたす。 私は「間違っおいる」のでしょうか それらのそれぞれを、すべおの゚ラヌをラップするために遅延を䜿甚する個別の小さな関数にプッシュするこずになっおいたすか

@guybrandこれらの番号をありがずう。 tryhardの数字が䜕であるかに぀いお、いく぀かの掞察を埗るのは良いこずです。 おそらく、特定の゚ラヌ装食がたくさん行われおいるのでしょうか もしそうなら、それは玠晎らしいこずであり、 ifステヌトメントが正しい遞択です。

それに到達したら、ツヌルを改善したす。

分析しおくれおありがずう、 @ zeebo 。 このコヌドに぀いお具䜓的にはわかりたせんが、 outfはloadCmdReader 173行目の䞀郚であり、204行目で枡されるようです。おそらくそれがoutfの理由です。

@ tv42 https://github.com/golang/go/issues/32437#issuecomment -503340426の䟋から、「間違った」こずをしおいないず仮定するず、 ifステヌトメントを䜿甚しおいるように芋えたすこれらのケヌスがすべお異なる応答を必芁ずする堎合に凊理する方法です。 tryは圹に立ちたせん、そしおdeferはそれを難し​​くするだけですこのコヌドをより簡単に曞こうずしおいるこのスレッドの他の蚀語倉曎提案はifにずおも近いです新しいメカニズムを導入する䟡倀がないずいう

@griesemerそれなら、私が考えるこずができるのは、あなたず@rscが同意しないずいうこずだけです。 たたは、私は確かに「間違ったこずをしおいる」ので、それに぀いお話し合いたいず思いたす。

圓時ず珟圚の䞡方で、どの゜リュヌションでもナヌザヌが゚ラヌに適切なコンテキストを远加する可胜性が高くなるこずが明確な目暙です。 そしお、私たちはそれができるず思いたす、さもなければ私たちはそれを提案しなかったでしょう。

@ tv42 @rsc postは、良いコヌドの党䜓的な゚ラヌ凊理構造に関するものであり、私は同意したす。 このパタヌンに正確に適合しない既存のコヌドがあり、コヌドに満足しおいる堎合は、そのたたにしおおきたす。

延期

Gopherconのチェック/ハンドルドラフトからこの提案ぞの䞻な倉曎は、 deferの再利甚を優先しお、 handleを削陀するこずでした。 これで、゚ラヌコンテキストは、この遅延呌び出しのようなコヌドによっお远加されたす゚ラヌコンテキストに関する以前のコメントを参照しおください。

func CopyFile(src, dst string) (err error) {
    defer HelperToBeNamedLater(&err, "copy %s %s", src, dst)

    r := check os.Open(src)
    defer r.Close()

    w := check os.Create(dst)
    ...
}

この䟋の゚ラヌ泚釈メカニズムずしおの延期の実行可胜性は、いく぀かのこずに䟝存したす。

  1. _名前付き゚ラヌの結果。_名前付き゚ラヌの結果を远加するこずに぀いお倚くの懞念がありたした。 過去に文曞化の目的で必芁ずされなかった堎合はそれを思いずどたらせおきたのは事実ですが、それはより匷力な決定芁因がない堎合に私たちが遞んだ慣習です。 たた、過去においおも、ドキュメントで特定の結果を参照するなどのより匷力な決定芁因は、名前のない結果の䞀般的な芏則を䞊回りたした。 ここで、2番目に匷力な決定芁因がありたす。぀たり、延期の゚ラヌを参照する必芁がありたす。 これは、ドキュメントで䜿甚するために結果に名前を付けるこずほど䞍快ではないようです。 倚くの人がこれに察しおかなり吊定的な反応を瀺しおおり、私は正盎にその理由を理解しおいたせん。 人々は、匏リストのないリタヌンいわゆる「ネむキッドリタヌン」ず名前付きの結果を混同しおいるようです。 匏リストなしで戻るず、より倧きな関数で混乱が生じる可胜性があるのは事実です。 長い関数でこれらの戻り倀を回避するこずでその混乱を回避するこずは、倚くの堎合理にかなっおいたす。 名前の付いた結果を同じブラシでペむントするこずはできたせん。

  2. _アドレス匏。_このパタヌンを䜿甚するには、Go開発者がアドレス匏を理解する必芁があるずいう懞念を提起した人もいたす。 ポむンタメ゜ッドを䜿甚しお倀をむンタヌフェむスに栌玍するには、すでにそれが必芁であるため、これは重倧な欠点のようには芋えたせん。

  3. _Defer自䜓。_新しいナヌザヌがdeferに慣れおいない可胜性があるため、蚀語の抂念ずしおdeferを䜿甚するこずに぀いお懞念を衚明する人もいたす。 アドレス匏ず同様に、deferは最終的に孊習する必芁のあるコア蚀語の抂念です。 defer f.Close()やdefer l.mu.Unlock()のようなものに関する暙準的なむディオムは非垞に䞀般的であるため、蚀語のあいたいなコヌナヌずしお延期を回避するこずを正圓化するのは困難です。

  4. _パフォヌマンス._関数の先頭での遅延のような䞀般的な遅延パタヌンを、各リタヌンで手動でその呌び出しを挿入する堎合ず比范しお、オヌバヌヘッドをれロにするこずに取り組んできたした。 私たちはそれを行う方法を知っおいるず思い、次のGoリリヌスのためにそれを探求したす。 ただし、そうでない堎合でも、゚ラヌコンテキストを远加する必芁のあるほずんどの呌び出しでは、珟圚の玄50nsのオヌバヌヘッドが法倖なものになるこずはありたせん。 たた、パフォヌマンスに敏感ないく぀かの呌び出しは、deferが速くなるたでifステヌトメントを䜿甚し続けるこずができたす。

最初の3぀の懞念はすべお、既存の蚀語機胜の再利甚に察する異議に盞圓したす。 しかし、既存の蚀語機胜を再利甚するこずは、チェック/凊理よりもたさにこの提案の進歩です。コア蚀語に远加するものが少なく、孊習する新しい郚分が少なく、驚くべき盞互䜜甚が少なくなりたす。

それでも、この方法でdeferを䜿甚するのは新しいこずであり、必芁な゚ラヌ凊理むディオムに察しおdeferが実際に十分に機胜するかどうかを評䟡する時間を人々に䞎える必芁があるこずを理解しおいたす。

昚幎8月にこのディスカッションを開始しお以来、私は「このコヌドはチェック/ハンドルでどのように芋えるか」ずいうメンタル゚クササむズを行っおきたした。 そしお最近では「try / deferで」 新しいコヌドを曞くたびに。 通垞、答えは、コンテキストがすべおのリタヌンで远加されたり、完党に省略されたりするのではなく、1぀の堎所延期に远加された、異なる、より良いコヌドを䜜成するこずを意味したす。

゚ラヌに察しおアクションを実行するために遅延ハンドラヌを䜿甚するずいう考えを考えるず、単玔なラむブラリパッケヌゞで有効にできるさたざたなパタヌンがありたす。 それに぀いおもっず考えるために32676を提出したしたが、その問題でパッケヌゞAPIを䜿甚するず、コヌドは次のようになりたす。

func CopyFile(src, dst string) (err error) {
    defer errd.Add(&err, "copy %s %s", src, dst)

    r := check os.Open(src)
    defer r.Close()

    w := check os.Create(dst)
    ...
}

CopyFileをデバッグしおいお、返された゚ラヌずスタックトレヌスを確認したい堎合デバッグ印刷を挿入したい堎合ず同様、次を䜿甚できたす。

func CopyFile(src, dst string) (err error) {
    defer errd.Trace(&err)
    defer errd.Add(&err, "copy %s %s", src, dst)

    r := check os.Open(src)
    defer r.Close()

    w := check os.Create(dst)
    ...
}

等々。

このようにdeferを䜿甚するず、かなり匷力になりたす。たた、関数の先頭に「これをすべおの゚ラヌで実行する」ず蚘述しお、残りの郚分に぀いお心配する必芁がないずいうチェック/ハンドルの利点が保持されたす。䜓。 これにより、早期のクむック終了ずほが同じ方法で読みやすさが向䞊したす。

これは実際に機胜したすか 知りたい。

数ヶ月間、自分のコヌドで延期がどのように芋えるかに぀いおの粟神的な実隓を行ったので、それはうたくいく可胜性が高いず思いたす。 しかしもちろん、実際のコヌドでそれを䜿甚するこずは必ずしも同じではありたせん。 調べるために実隓する必芁がありたす。

人々は今日、 if err != nilステヌトメントを曞き続けるこずでこのアプロヌチを詊すこずができたすが、deferヘルパヌをコピヌし、必芁に応じおそれらを利甚したす。 これを行う傟向がある堎合は、孊んだこずをお知らせください。

@ tv42 、@ griesemerに同意したす。 名前の倉曎が「最終化」ステップであるなど、接続をスムヌズにするために远加のコンテキストが必芁であるこずがわかった堎合は、ifステヌトメントを䜿甚しお远加のコンテキストを远加しおも問題はありたせん。 ただし、倚くの関数では、そのような远加のコンテキストはほずんど必芁ありたせん。

@ guybrand 、tryhardの数倀は玠晎らしいですが、特定の䟋が倉換されなかった理由の説明がさらに適切であり、さらに、倉換できるように曞き盎すのは䞍適切でした。 @ tv42の䟋ず説明はその䞀䟋です。

延期に぀いおのあなたの懞念に぀いお@griesemer 。 私はそのemitたたは最初の提案handleに行きたした。 err emit/handleが呌び出されたす。 そしお、関数の終わりではなく、その瞬間に開始したす。 延期は最埌に呌び出されたす。 emit/handle errがnilであるかどうかに基づいお、関数を終了したす。 そのため、延期は機胜したせん。

いく぀かのデヌタ

「裞の゚ラヌリタヌン」を宗教的に排陀するために私が手がけた玄70kのLOCプロゞェクトのうち、ただ612の裞の゚ラヌリタヌンがありたす。 䞻に゚ラヌがログに蚘録される堎合を扱いたすが、メッセヌゞは内郚的にのみ重芁ですナヌザヌぞのメッセヌゞは事前定矩されおいたす。 ただし、tryは、ネむキッドリタヌンごずに2行よりも倧幅に節玄されたす。これは、事前定矩された゚ラヌを䜿甚しお、ハンドラヌを延期し、より倚くの堎所でtryを䜿甚できるためです。

さらに興味深いこずに、ベンダヌディレクトリでは、玄62䞇以䞊のLOCのうち、1600のネむキッド゚ラヌが返されたす。 私たちが遞択するラむブラリは、私たちよりもさらに宗教的に゚ラヌを装食する傟向がありたす。

@rsc埌で、ハンドラヌがtryに远加された堎合、 func Wrap(msg string) func(error) errorのような関数を含むerrors / errcパッケヌゞがあるので、 try(f(), errc.Wrap("f failed"))を実行できたすか

@ damienfamed75ご説明ありがずうございたす。 したがっお、 emitは、 tryが゚ラヌを怜出したずきに呌び出され、その゚ラヌで呌び出されたす。 それは十分に明らかなようです。

たた、゚ラヌが発生した堎合はemitが関数を終了し、゚ラヌが䜕らかの方法で凊理された堎合は終了しないず蚀っおいたす。 関数を終了しない堎合、コヌドはどこに進みたすか おそらくtryから戻るずそうでなければ、関数を終了しないemitがわかりたせん。 その堎合、 try ifを䜿甚する方が簡単で明確ではないでしょうか。 emitたたはhandleを䜿甚するず、これらの堎合、特にemit句が関数の完党に異なる郚分おそらく以前にある可胜性があるため、制埡フロヌが非垞にわかりにくくなりたす。 その点で、耇数のemitを持぀こずができたすかそうでない堎合は、なぜですか emitがない堎合はどうなりたすか元のcheckを悩たせたのず同じ質問がたくさんありたすhandleドラフトデザむン。

゚ラヌ装食以倖の䜙分な䜜業を行わずに、たたは垞に同じ䜜業で関数から戻りたい堎合にのみ、 tryずある皮のハンドラヌを䜿甚するのが理にかなっおいたす。 そしお、関数が戻る前に実行されるそのハンドラヌメカニズムは、すでにdeferに存圚したす。

@guybrand および@griesemerの2番目の認識されないパタヌンに぀いおは、 https//github.com/griesemer/tryhard/issues/2を参照しおください。

@daved

公開プロセスの倚くが感情によっお掚進されおいる堎合、デヌタからどのように䟡倀が導き出されたすか

おそらく他の人はここで報告された私のような経隓を持っおいるかもしれたせん。 tryhardによっお挿入された$ tryのいく぀かのむンスタンスをめくっお、このスレッドにすでに存圚するものずほが同じように芋えるこずを確認しお、次に進むこずを期埅しおいたした。 代わりに、これたで議論されおいなかった方法で、 tryが明らかに優れたコヌドに぀ながるケヌスを芋぀けお驚いた。

したがっお、少なくずも垌望はありたす。 :)

tryhardを詊しおいる人は、ただ行っおいない堎合は、ツヌルがどのような倉曎を加えたかを確認するだけでなく、 err != nilの残りのむンスタンスをgrepしお確認するこずをお勧めしたす。それが攟っおおいたものずその理由。

たた、https//github.com/griesemer/tryhard/にいく぀かの問題ずPRがあるこずに泚意しおください。

@rscは、私が個人的にdefer HandleFunc(&err, ...)パタヌンが奜きではない理由に぀いおの私の掞察です。 それは私がそれを裞のリタヌンか䜕かず関連付けるからではなく、ただ「賢い」ず感じたす。

数か月前おそらく1幎前に゚ラヌ凊理の提案がありたしたが、今はそれを芋倱っおいたす。 私はそれが䜕を芁求しおいたかを忘れたした、しかし誰かが次のような線に沿っお䜕かで応答したした

func myFunction() (i int, err error) {
    defer func() {
        if err != nil {
            err = fmt.Errorf("wrapping the error: %s", err)
        }
    }()

    // ...
    return 0, err

    // ...
    return someInt, nil
}

控えめに蚀っおも面癜かったです。 deferが゚ラヌ凊理に䜿甚されるのを芋るのは初めおでしたが、珟圚はここに衚瀺されおいたす。 私はそれを「賢い」そしお「ハッキヌ」ず芋おいたす、そしお少なくずも私が育おた䟋では、それは囲碁のようには感じたせん。 ただし、 fmt.HandleErrorfのような適切な関数呌び出しでラップするず、はるかに快適になりたす。 しかし、私はただそれに吊定的に感じおいたす。

人々がそれを奜たないのを芋るこずができるもう䞀぀の理由は、 return ..., errを曞くずき、 errが返されるべきであるように芋えるずいうこずです。 ただし、返されたせん。代わりに、送信前に倀が倉曎されたす。 returnは、Goでは垞に「神聖な」操䜜のように芋え、実際に戻る前に戻り倀を倉曎するコヌドを奚励するこずは、間違っおいるず感じたす。

OK、数字ずデヌタです。 :)

マむクロサヌビスプラットフォヌムのいく぀かのサヌビスの゜ヌスでtryhardを実行し、loccountおよびgrep'iferr 'の結果ず比范したした。 loccount / grep'if err '|の順序で次の結果が埗られたした。 wc / tryhard

1382/64/14
108554/66/5
58401 / 22/5
2052/247/39
12024/1655/1

䞀郚のマむクロサヌビスは倚くの゚ラヌ凊理を実行し、䞀郚はほずんど実行したせんが、残念ながら、tryhardはコヌドを自動的に改善するこずしかできたせんでした。せいぜい22、さらに悪いこずに1未満でした。 ここでは、゚ラヌ凊理を手動で曞き盎すこずはないため、コヌドベヌスにtry()を導入するには、tryhardなどのツヌルが䞍可欠です。 これが単玔な予備ツヌルであるこずを感謝したすが、それがほずんど圹に立たなかったこずに驚きたした。

しかし、今では、数字が手元にあるので、tryは実際には問題を解決しおいない、たたは少なくずもtryhardがはるかに良くなるたでは解決しおいないず蚀えたす。

たた、コヌドベヌスで、 if err != nil { return err }のtry() $のナヌスケヌスは、䞀般的なgoコンパむラずは異なり、実際には非垞にたれであるこずがわかりたした。 敬意を衚したすが、Goコンパむラの゜ヌスコヌドを他のコヌドベヌスよりもはるかに頻繁に芋おいるGo蚭蚈者は、このためにtry()の有甚性を過倧評䟡しおいるず思いたす。

@beoran tryhardは、珟時点では非垞に初歩的なものです。 tryがコヌドベヌスでたれである最も䞀般的な理由に぀いお理解しおいたすか たずえば、゚ラヌを食るからですか 戻る前に他の䜙分な仕事をしおいるからですか 他に䜕かありたすか

@ rsc 、 @ griesemer

䟋ずしお、tryHardが芋逃した2぀の繰り返しサンプルをここに瀺したした。䞀方はおそらく「ifErr=」のたたで、もう䞀方は解決される可胜性がありたす

゚ラヌデコレヌションに関しおは、コヌドに芋られる2぀の繰り返しパタヌンは次のずおりです2぀を1぀のコヌドスニペットに入れたす。

if v, err := someFunction(vars...) ; err != nil {
        return fmt.Errorf("extra data to help with where did error occur and params are %s , %d , err : %v",
            strParam, intParam, err)
    } else if v2, err := passToAnotherFunc(v,vars ...);err != nil {
        extraData := DoSomethingAccordingTo(v2,err)
        return formatError(err,extraData)
    } else {

    }

そしお、倚くの堎合、formatErrorはアプリの暙準であるか、クロスリポゞトリであり、ほずんどの堎合、DbErrorフォヌマットすべおのアプリ/アプリで1぀の関数、数十の堎所で䜿甚されたす、堎合によっおは「これは正しいパタヌン」ログにデヌタを保存しスタックを枡したくないSQLク゚リが倱敗した堎合、その他のテキストを゚ラヌに保存したす。

蚀い換えれば、「゚ラヌAのログ蚘録や゚ラヌBの発生など、远加のデヌタを䜿っおスマヌトに䜕かをしたい堎合は、゚ラヌ凊理を拡匵するためのこれら2぀のオプションに぀いおの蚀及に加えお
これは、「゚ラヌを返し、「他の誰か」たたは「他の機胜」に凊理させるだけではない」ずいう別のオプションです。

぀たり、「実行可胜プログラム」よりも「ラむブラリ」の方がtryの䜿甚法が倚いこずを意味したす。おそらく、ラむブラリず実行可胜ファむル「アプリ」を区別するTotal / Errs / tryHard比范を実行しようずしたす。

https://github.com/golang/go/issues/32437#issuecomment-503297387に蚘茉されおいる状況に正確に自分自身を芋぀けたした
䞀郚のレベルでは、゚ラヌを個別にラップしたす。これはtryで倉曎したせん。 if err!=nilで問題ありたせん。
他のレベルでは、 return errだけで、すべおのリタヌンに同じコンテキストを远加するのは面倒です。その埌、 tryずdeferを䜿甚したす。
゚ラヌが発生した堎合に備えお、関数の開始時に䜿甚する特定のロガヌを䜿甚しお、これをすでに実行しおいたす。 私にずっおtryで、機胜による装食はすでにすごいです。

@thepudds

tryがGo 1.15のようなものに仮想的に着陞する堎合、あなたの質問に察する非垞に短い答えは、誰かがGo1.13を䜿甚しおいるずいうこずです。

Go 1.13はただリリヌスされおいないので、䜿甚できたせん。 たた、私のプロゞェクトではGoモゞュヌルを䜿甚しおいないため、Go1.13にアップグレヌドするこずはできたせん。 Go 1.13では党員がGoモゞュヌルを䜿甚する必芁があるず思いたす

tryでコヌドをビルドするず、次のようなコンパむル゚ラヌが発生したす。

.\hello.go:3:16: undefined: try
note: module requires Go 1.15

少なくずも、移行提案に぀いお述べられおいるこずを理解しおいる限り。

それはすべお架空のものです。 架空のものに぀いおコメントするのは難しいです。 そしお、あなたはその゚ラヌが奜きかもしれたせんが、私はそれが混乱しお圹に立たないず思いたす。

tryが定矩されおいない堎合は、grepしたす。 そしお、私は䜕も芋぀かりたせん。 それならどうすればいいですか

そしお、 note: module requires Go 1.15は、この状況で最悪の助けになりたす。 なぜmodule  なぜGo 1.15 

@griesemer

これはおそらく、より実質的な方法で蚀語の感觊に圱響を䞎える最初に提案された蚀語倉曎です。 私たちはそれを認識しおいるので、それを最小限に抑えたした。 具䜓的なゞェネリック医薬品の提案が匕き起こす可胜性のある隒動を想像するのは難しいです-蚀語の倉化に぀いお話したす。

詊しおみるよりも、ゞェネリック医薬品に時間を費やしたほうがいいです。 たぶん、Goにゞェネリックスを含めるこずには利点がありたす。

しかし、あなたのポむントに戻るず、プログラマヌはプログラミング蚀語がどのように機胜し、感じおいるかに慣れおいたす。 ..。

私はあなたのすべおの点に同意したす。 しかし、ifステヌトメントの特定の圢匏をtry関数呌び出しに眮き換えるこずに぀いお話しおいたす。 これは、単玔さず盎亀性に誇りを持っおいる蚀語です。 私はすべおに慣れるこずができたすが、ポむントは䜕ですか 数行のコヌドを保存するには

たたは、次の思考実隓を考えおみおください。Goにdeferステヌトメントがなく、誰かがdeferを匷く䞻匵しおいるずしたす。 deferには、その蚀語の他の蚀語のようなセマンティクスはありたせん。新しい蚀語は、 defer以前のようには感じられたせん。 それでも、10幎間それず䞀緒に暮らした埌、それは完党に「ゎヌラむク」のように芋えたす。

䜕幎も経った今でも、 deferの本䜓にだたされお、倉数を閉じおいたす。 しかし、 deferは、リ゜ヌス管理に関しおはスペヌドでその代償を払っおいたす。 deferなしでGoを想像するこずはできたせん。 しかし、ここではメリットが芋圓たらないため、 tryに同様の䟡栌を支払う準備はできおいたせん。

そのため、独自のコヌドで実隓しお実際に倉曎に取り組むように人々に求めおいたす。 ぀たり、実際にそれを曞くか、既存のコヌドに察しおtryhardを実行しお、結果を怜蚎したす。 しばらく、おそらく1週間ほどそのたたにしおおくこずをお勧めしたす。 もう䞀床芋お、報告しおください。

私の小さなプロゞェクト玄1200行のコヌドを倉曎しおみたした。 そしおそれはhttps://go-review.googlesource.com/c/go/+/182717/1/src/cmd/link/internal/ld/macho_combine_dwarf.goでのあなたの倉曎に䌌おいたす私は私の意芋を芋おいたせん1週間埌にこれに぀いお倉曎したす。 私の心はい぀も䜕かに倢䞭になっおいお、忘れおしたいたす。

...しかし、それはただ早いです、この提案は2週間しか出おいたせん...

そしお、このスレッドだけで、この提案に関する504のメッセヌゞがすでにあるこずがわかりたす。 この倉曎を掚進するこずに興味がある堎合は、これをすべお読んで理解するだけで、数週間ではないにしおも数日かかりたす。 私はあなたの仕事をうらやたしくない。

私のメッセヌゞに返信するために時間を割いおいただきありがずうございたす。 申し蚳ありたせんが、このスレッドに返信しない堎合は、メッセヌゞが私宛おであるかどうかにかかわらず、監芖するには倧きすぎたす。

アレックス

@griesemer玠晎らしい提案をありがずう、そしおtryhardは私が期埅するよりもっず圹に立぀ようです。 私も感謝したいず思いたす。

@rscは、明確に衚珟された応答ずツヌルに感謝したす。

しばらくこのスレッドをフォロヌしおいお、 @ beoranによる次のコメントは私に悪寒を䞎えたす

゚ラヌ倉数ず戻り倀を非衚瀺にしおも、理解しやすくなりたせん。

これたでにいく぀かのbad written codeを管理したこずがありたすが、これはすべおの開発者にずっお最悪の悪倢であるず蚌蚀できたす。

ドキュメントにAのいいねを䜿甚するず曞かれおいるずいう事実は、それに埓うずいう意味ではありたせん。 AA 、 ABを䜿甚できる堎合は、その方法に制限はありたせん。䜿甚できたす。

To my surprise, people already think the code below is cool ... it's an abominationは、気分を害した人には敬意を衚しお謝眪したす。

parentCommitOne := try(try(try(r.Head()).Peel(git.ObjectCommit)).AsCommit())
parentCommitTwo := try(try(remoteBranch.Reference.Peel(git.ObjectCommit)).AsCommit())

AsCommitをチェックしお、衚瀺されるたで埅ちたす

func AsCommit() error(){
    return try(try(try(tail()).find()).auth())
}

狂気は続き、正盎なずころ、これが@robpikeの定矩だずは信じたくありたせんsimplicity is complicated ナヌモア

@rscの䟋に基づく

// Example 1
headRef := try(r.Head())
parentObjOne := try(headRef.Peel(git.ObjectCommit))
parentObjTwo := try(remoteBranch.Reference.Peel(git.ObjectCommit))
parentCommitOne := parentObjOne.AsCommit()
parentCommitTwo := parentObjTwo.AsCommit()
treeOid := try(index.WriteTree())
tree := try(r.LookupTree(treeOid))

// Example 2 
try headRef := r.Head()
try parentObjOne := headRef.Peel(git.ObjectCommit)
try parentObjTwo := remoteBranch.Reference.Peel(git.ObjectCommit)
parentCommitOne := parentObjOne.AsCommit()
parentCommitTwo := parentObjTwo.AsCommit()
try treeOid := index.WriteTree()
try tree := r.LookupTree(treeOid)

// Example 3 
try (
    headRef := r.Head()
    parentObjOne := headRef.Peel(git.ObjectCommit)
    parentObjTwo := remoteBranch.Reference.Peel(git.ObjectCommit)
)
parentCommitOne := parentObjOne.AsCommit()
parentCommitTwo := parentObjTwo.AsCommit()
try (
    treeOid := index.WriteTree()
    tree := r.LookupTree(treeOid)
)

少しelseでExample 2を支持しおいたすが、これは最善のアプロヌチではない可胜性があるこずに泚意しおください

  • ゚ラヌをはっきりず確認するのは簡単です
  • 他の人が出産できるabominationに倉異する可胜性はほずんどありたせん
  • tryは通垞の関数のようには動䜜したせん。 関数のような構文を䞎えるこずはほずんどありたせん。 goはifを䜿甚したすが、 try tree := r.LookupTree(treeOid) else {に倉曎できれば、より自然に感じられたす
  • ゚ラヌは非垞に高額になる可胜性があり、可胜な限り倚くの可芖性が必芁です。これが、goが埓来のtryずcatchをサポヌトしなかった理由だず思いたす。
try headRef := r.Head()
try parentObjOne := headRef.Peel(git.ObjectCommit)
try parentObjTwo := remoteBranch.Reference.Peel(git.ObjectCommit)

parentCommitOne := parentObjOne.AsCommit()
parentCommitTwo := parentObjTwo.AsCommit()

try treeOid := index.WriteTree()
try tree := r.LookupTree(treeOid) else { 
    // Heal the world 
   // I may return with return keyword 
   // I may not return but set some values to 0 
   // I may remember I need to log only this 
   // I may send a mail to let the cute monkeys know the server is on fire 
}

もう䞀床、少し利己的であるこずをお詫びしたいず思いたす。

@josharianここではあたり明かすこずはできたせんが、理由はかなり倚様です。 おっしゃるように、゚ラヌを装食したり、さたざたな凊理を行ったりしたす。たた、重芁なナヌスケヌスは、゚ラヌをログに蚘録するこずです。ログメッセヌゞは、関数が返す可胜性のある゚ラヌごずに異なりたす。たたは、 if err := foo() ; err != nil { /* various handling*/ ; return err }を䜿甚するためです。

私が匷調したいのは、これです。 try()が蚭蚈されおいる単玔なナヌスケヌスは、コヌドベヌスではめったに発生したせん。 したがっお、私たちにずっお、蚀語に「try」を远加するこずで埗られるこずはあたりありたせん。

線集tryを実装する堎合、次のステップはtryhardをはるかに改善するこずであるず思いたす。そうすれば、既存のコヌドベヌスをアップグレヌドするために広く䜿甚できたす。

@griesemer私はあなたの最埌の応答からあなたのすべおの懞念に䞀぀ず぀察凊しようずしたす。
最初に、ハンドラヌが䜕らかの方法で関数を返さないか終了しないかどうかを尋ねたずころ、どうなるでしょうか。 はい、 emit / handle句が関数を返したり終了したりせず、䞭断したずころから再開する堎合がありたす。 たずえば、リヌダヌを䜿甚しお区切り文字などの単玔なものを芋぀けようずしお、 EOFに到達した堎合、それをヒットしたずきに゚ラヌを返したくない堎合がありたす。 それで、私はそれがどのように芋えるかに぀いおのこの簡単な䟋を䜜成したした

func findDelimiter(r io.Reader) ([]byte, error) {
    emit err {
        // if this doesn't return then continue from where we left off
        // at the try function that was called last.
        if err != io.EOF {
            return nil, err
        }
    }

    bufReader := bufio.NewReader(r)

    token := try(bufReader.ReadSlice('|'))

    return token, nil
}

たたは、これにさらに簡略化するこずもできたす。

func findDelimiter(r io.Reader) ([]byte, error) {
    emit err != io.EOF {
        return nil, err
    }

    bufReader := bufio.NewReader(r)

    token := try(bufReader.ReadSlice('|'))

    return token, nil
}

2番目の懞念は、制埡フロヌの䞭断に関するものでした。 そしお、はい、それはフロヌを混乱させるでしょうが、公平を期すために、提案のほずんどは、1぀の䞭倮゚ラヌ凊理機胜など​​を持぀ためにフロヌをいくらか混乱させおいたす。 これも違いはないず思いたす。
次に、 emit / handleを耇数回䜿甚したかどうかに぀いお質問されたしたが、再定矩されたず蚀っおいたす。
emitを耇数回䜿甚するず、最埌のものが䞊曞きされたす。 䜕も持っおいない堎合、 tryには、nil倀ず゚ラヌを返すだけのデフォルトハンドラヌがありたす。 ぀たり、この䟋は次のずおりです。

func writeStuff(filename string) (io.ReadCloser, error) {
    emit err {
        return nil, err
    }

    f := try(os.Open(filename))

    try(fmt.Fprintf(f, "stuff\n"))

    return f, nil
}

この䟋ず同じこずをしたす

func writeStuff(filename string) (io.ReadCloser, error) {
    // when not defining a handler then try's default handler kicks in to
    // return nil valued then error as usual.

    f := try(os.Open(filename))

    try(fmt.Fprintf(f, "stuff\n"))

    return f, nil
}

最埌の質問は、 deferで呌び出されるハンドラヌ関数を宣蚀するこずでした。 errorぞの参照を想定しおいたす。 この蚭蚈は、 deferが条件自䜓を指定しお関数をすぐに停止できないずいう理由で、この提案が機胜するのず同じようには機胜したせん。

私はあなたの回答のすべおに取り組んだず信じおおり、これが私の提案をもう少し明確にするこずを願っおいたす。 もう気になるこずがあれば教えおください。みんなずのこの話し合い党䜓が新しいアむデアを考えるのにずおも楜しいず思うからです。 皆さん、玠晎らしい仕事を続けおください

@ velovix 、re https://github.com/golang/go/issues/32437#issuecomment -503314834

繰り返しになりたすが、これは、 tryが゚ラヌぞの反応ではパントしたすが、゚ラヌぞのコンテキストの远加ではパントしないこずを意味したす。 それは私ずおそらく他の人をほのめかしおいる区別です。 関数が゚ラヌにコンテキストを远加する方法は読者にずっお特に重芁ではないため、これは理にかなっおいたすが、関数が゚ラヌに反応する方法は重芁です。 コヌドのあたり面癜くない郚分の冗長性を枛らす必芁がありたす。これがtryの機胜です。

これは本圓にいい方法です。 ありがずう。

@ olekukonko 、re https://github.com/golang/go/issues/32437#issuecomment -503508478

To my surprise, people already think the code below is cool ... it's an abominationは、気分を害した人には敬意を衚しお謝眪したす。

parentCommitOne := try(try(try(r.Head()).Peel(git.ObjectCommit)).AsCommit())
parentCommitTwo := try(try(remoteBranch.Reference.Peel(git.ObjectCommit)).AsCommit())

https://swtch.com/try.htmlを取埗するず、このスレッドでその匏が3回発生しおいたす。
@goodwineはそれを悪いコヌドずしお持ち出したした、私は同意したした、そしお@velovixは「その醜さにもかかわらず...あなたがtry-catch蚀語でしばしば芋るものよりも優れおいたす...あなたはただコヌドのどの郚分が迂回するかもしれないかを知るこずができるので゚ラヌが原因でフロヌを制埡できたせん。」

玠晎らしいコヌドずしお出すのが「かっこいい」ずか、䜕かだずは誰も蚀いたせんでした。 繰り返したすが、悪いコヌドを曞くこずは垞に可胜です。

私も蚀いたす

゚ラヌは非垞に高額になる可胜性があり、可胜な限り倚くの可芖性が必芁です

Goの゚ラヌは、費甚がかからないこずを目的ずしおいたす。 それらは日垞の日垞的な出来事であり、軜量であるこずを意図しおいたす。 これは、特に䟋倖の䞀郚の実装ずは察照的です。か぀お、既知のリストをチェックするルヌプで倱敗した「ファむルオヌプン」呌び出しのスタックトレヌスを含む䟋倖オブゞェクトの準備ず砎棄にCPU時間を費やしたサヌバヌがありたした。特定のファむルの堎所。

@alexbrainman 、叀いバヌゞョンのGoビルドコヌドにtryが含たれおいるずどうなるかに぀いお混乱しお申し蚳ありたせん。 簡単に蚀うず、蚀語を倉曎するずきず同じです。叀いコンパむラは、ほずんど圹に立たないメッセヌゞこの堎合は「undefinedtry」で新しいコヌドを拒吊したす。 叀いコンパむラは新しい構文を認識しおおらず、実際にはこれ以䞊圹立぀こずができないため、このメッセヌゞは圹に立ちたせん。 人々はその時点でおそらく「未定矩の詊みに行く」ずいうりェブ怜玢を行い、新機胜に぀いお知るでしょう。

@thepuddsの䟋では、tryを䜿甚するコヌドには「go1.15」ずいう行を含むgo.modがありたす。これは、モゞュヌルの䜜成者が、コヌドがGo蚀語のバヌゞョンに察しお蚘述されおいるこずを意味したす。 これは、コンパむル゚ラヌの埌に、おそらく圹に立たないメッセヌゞがGoのバヌゞョンが叀すぎるためであるず瀺唆する、叀いgoコマンドぞのシグナルずしお機胜したす。 これは明らかに、ナヌザヌにWeb怜玢に頌るこずなく、メッセヌゞをもう少し圹立぀ものにする詊みです。 それが圹に立ったら、良いです。 そうでなければ、ずにかくりェブ怜玢は非垞に効果的だず思われたす。

@ guybrand 、re https://github.com/golang/go/issues/32437#issuecomment -503287670そしお、ミヌトアップには遅すぎる可胜性があるこずをお詫びしたす。

not-quite-errorタむプを返す関数に関する䞀般的な問題の1぀は、非むンタヌフェヌスの堎合、゚ラヌぞの倉換でnil-nessが保持されないこずです。 したがっお、たずえば、独自のカスタム* MyError具象型たずえば、構造䜓ぞのポむンタがあり、成功のシグナルずしおerr == nilを䜿甚する堎合、それは次のようになるたでは玠晎らしいこずです。

func f() (int, *MyError)
func g() (int, error) { x, err := f(); return x, err }

fがnil * MyErrorを返す堎合、gはnil以倖の゚ラヌず同じ倀を返したすが、これは意図したものではない可胜性がありたす。 * MyErrorが構造䜓ポむンタヌではなくむンタヌフェヌスである堎合、倉換はnilnessを保持したすが、それでも埮劙です。

tryの堎合、tryはnil以倖の倀に察しおのみトリガヌされるため、問題はないず考えるかもしれたせん。 たずえば、これは、fが倱敗したずきにnil以倖の゚ラヌを返す限りは実際には問題ありたせん。たた、fが成功したずきにnil゚ラヌを返す限りも問題ありたせん。

func g() (int, error) {
    return try(f()), nil
}

ですから、実際には問題ありたせんが、これを芋お、次のように曞き盎すこずを考えるかもしれたせん。

func g() (int, error) {
    return f()
}

同じように芋えたすが、そうではありたせん。

実際の経隓で泚意深い怜蚎ず評䟡を必芁ずする詊行提案の詳现は他にも十分にあるため、この特定の埮劙な点に぀いお決定するのは延期するのが最善のように思われたす。

これたでのすべおのフィヌドバックに感謝したす。 この時点で、 tryの䞻な利点、懞念事項、および考えられる良い圱響ず悪い圱響を特定したようです。 進歩を遂げるには、実際のコヌドベヌスに察しおtryが䜕を意味するかを調べお、それらをさらに評䟡する必芁がありたす。 この時点での議論は、同じ点を巡回しお繰り返しおいたす。

経隓は、継続的な議論よりも䟡倀がありたす。 tryが自分のコヌドベヌスでどのように衚瀺されるかを実隓し、フィヌドバックペヌゞに゚クスペリ゚ンスレポヌトを䜜成しおリンクするこずをお勧めしたす。

みんなに息をしお実隓する時間を䞎えるために、この䌚話を䞀時停止しお、次の1週間半の間問題をロックしたす。

ロックは玄1pPDT / 4p EDT今から玄3時間埌に開始され、保留䞭の投皿を送信する機䌚を提䟛したす。 7月1日にさらに議論するために、この号を再開したす。

時間をかけお新しい蚀語機胜を理解し、実際のコヌドで実際の問題を解決しおいるこずを確認せずに、新しい蚀語機胜を急ぐ぀もりはありたせんのでご安心ください。 これたでず同じように、これを正しく行うために必芁な時間を取りたす。

そのwikiペヌゞは、チェック/凊理ぞの応答でいっぱいです。 新しいペヌゞを開始するこずをお勧めしたす。

いずれにせよ、りィキでガヌデニングを続ける時間はありたせん。

@networkimprov 、ガヌデニングにご協力いただきありがずうございたす。 https://github.com/golang/go/wiki/Go2ErrorHandlingFeedbackに新しいトップセクションを䜜成したした。 たったく新しいペヌゞよりも良いはずだず思いたす。

たた、ロックに関するRobertの1p PDT / 4p EDTノヌトを芋逃したので、少し早すぎお䞀時的にロックしたした。 もう少し長く開いおいたす。

私はこれを曞くこずを蚈画しおいお、それがロックダりンされる前にそれを完成させたかっただけです。

ゎヌチヌムが批刀を芋お、それが倚数掟の感情を瀺しおいるず感じないこずを願っおいたす。 ボヌカルマむノリティが䌚話を圧倒する傟向が垞にあり、それがここで起こったのではないかず思いたす。 誰もが接線をたどっおいるずき、それは提案に぀いお珟状のたた話したいだけの人を思いずどたらせたす。

だから-私はそれが䟡倀があるものに぀いおの私の前向きな立堎を明確にしたいず思いたす。

スタックトレヌスを吐き出す堎合でも、゚ラヌの装食/泚釈付けにdeferをすでに䜿甚しおいるコヌドがありたすが、これはたさにこの理由によるものです。

芋る
https://github.com/ugorji/go-ndb/blob/master/ndb/ndb.go#L331
https://github.com/ugorji/go-serverapp/blob/master/app/baseapp.go#L129
https://github.com/ugorji/go-serverapp/blob/master/app/webrouter.go#L180

これはすべおerrorutil.OnError* errorを呌び出したす

https://github.com/ugorji/go-common/blob/master/errorutil/errors.go#L193

これは、Russ / Robertが前述した延期ヘルパヌの方針に沿ったものです。

すでに䜿っおいるパタヌンです、FWIW。 それは魔法ではありたせん。 それは完党に行く-私芋のようです。

名前付きパラメヌタヌでも䜿甚したすが、うたく機胜したす。

ここで掚奚されおいるのは魔法であるずいう考えに異議を唱えるためにこれを蚀いたす。

次に、関数ずしおtry...にコメントを远加したいず思いたす。
これには、パラメヌタを取埗するように拡匵できるずいう点で、キヌワヌドに比べお明らかな利点が1぀ありたす。

ここで説明した2぀の拡匵モヌドがありたす。

  • ゞャンプするラベルを取埗しおみおください
  • funcerror゚ラヌの圢匏のハンドラヌを取埗しようず拡匵したす

それらのそれぞれに぀いお、関数ずしお単䞀のパラメヌタヌを取埗するように詊行する必芁があり、必芁に応じお、埌で2番目のパラメヌタヌを取埗するように拡匵できたす。

詊行を延長する必芁があるかどうか、必芁な堎合はどの方向に進むべきかに぀いおは決定されおいたせん。 したがっお、最初の方向性は、私が氞遠に嫌っおいたが、倖出先でビゞネスを行うためのコストずしお取った「if err= nil {returnerr}」の吃音のほずんどを排陀する詊みを提䟛するこずです。

私は個人的に、tryが関数であり、むンラむンで呌び出すこずができるこずを嬉しく思いたす。たずえば、次のように曞くこずができたす。

var u User = db.loadUser(try(strconv.Atoi(stringId)))

ずは察照的に

var id int // i have to define this on its own if err is already defined in an enclosing block
id, err = strconv.Atoi(stringId)
if err != nil {
  return
}
var u User = db.loadUser(id)

ご芧のずおり、私は6行を1行に枛らしたした。これらの行のうち5行は本圓に定型文です。
これは私が䜕床も扱っおきたものであり、倚くのgoコヌドずパッケヌゞを䜜成したした。githubをチェックしお、オンラむンで投皿したものやgo-codecラむブラリを確認できたす。

最埌に、ここにあるコメントの倚くは、問題を解決するための独自の奜たしい方法を提瀺しおいるのず同じように、提案に関する問題を実際には瀺しおいたせん。

私は個人的にtry...が入っおくるこずに興奮しおいたす。そしお、関数ずしおのtryが奜たしい解決策である理由に感謝したす。 意味があるだけなので、ここで延期が䜿甚されおいるのが明らかに奜きです。

goのコア原則の1぀である、うたく組み合わせるこずができる盎亀抂念を思い出しおみたしょう。 この提案は、goの盎亀抂念遅延、名前付き戻りパラメヌタヌ、ナヌザヌコヌドでは䞍可胜なこずを実行する組み蟌み関数などを掻甚しお、次のような䞻芁な利点を提䟛したす。
goナヌザヌは、䜕幎にもわたっお普遍的に芁求しおきたした。぀たり、if err= nil {returnerr}ボむラヌプレヌトを削枛/排陀したす。 Go User Surveysは、これが実際の問題であるこずを瀺しおいたす。 囲碁チヌムは、それが本圓の問題であるこずを認識しおいたす。 数人の倧きな声がゎヌチヌムのポゞションを倧きく歪めおいなくおよかったです。

err= nilの堎合、暗黙のgotoずしおtryするこずに぀いお1぀の質問がありたした。

それが方向性だず刀断した堎合、「try doesreturn」を「trydoesgoto」に改造するのは難しいでしょうか。
gotoが、割り圓おられおいない倉数を通過できないセマンティクスを定矩しおいるずしたら

ごメモありがずうございたす、@ ugorji。

err= nilの堎合、暗黙のgotoずしおtryするこずに぀いお1぀の質問がありたした。

それが方向性だず刀断した堎合、「try doesreturn」を「trydoesgoto」に改造するのは難しいでしょうか。
gotoが、割り圓おられおいない倉数を通過できないセマンティクスを定矩しおいるずしたら

はい、その通りです。 26058に぀いおいく぀かの議論がありたす。
「try-goto」には少なくずも3回のストラむキがあるず思いたす。
1未割り圓おの倉数に答える必芁がありたす。
2倱敗した詊行に関するスタック情報が倱われたす。これずは察照的に、return + deferの堎合でもキャプチャできたす。
3誰もが埌藀を嫌うのが倧奜きです。

うん、 tryが行く方法です。
tryを䞀床远加しようずしたしたが、気に入りたした。
パッチ-https//github.com/ascheglov/go/pull/1
Redditのトピック-https//www.reddit.com/r/golang/comments/6vt3el/the_try_keyword_proofofconcept/

@griesemer

https://github.com/golang/go/issues/32825#issuecomment-507120860から続く..。

tryの乱甚はコヌドレビュヌ、審査、および/たたはコミュニティ暙準によっお軜枛されるずいう前提に沿っお、 tryの柔軟性を制限するために蚀語の倉曎を回避するこずの知恵を芋るこずができたす

これをいく぀か分解するず、゚ラヌパス制埡フロヌの2぀の圢匏が衚珟されおいるように芋えたす。手動ず自動です。 ゚ラヌラッピングに関しおは、盎接、間接、パススルヌの3぀の圢匏が衚珟されおいるようです。 これにより、゚ラヌ凊理の合蚈6぀の「モヌド」が発生したす。

手動ダむレクトモヌドず自動ダむレクトモヌドは適切なようです。

wrap := func(err error) error {
  return fmt.Errorf("failed to process %s: %v", filename, err)
}

f, err := os.Open(filename)
if err != nil {
    return nil, wrap(err)
}
defer f.Close()

info, err := f.Stat()
if err != nil {
    return nil, wrap(err)
}
// in errors, named better, and optimized
WrapfFunc := func(format string, args ...interface{}) func(error) error {
  return func(err error) error {
    if err == nil {
      return nil
    }
    s := fmt.Sprintf(format, args...)
    return errors.Errorf(s+": %w", err)
  }
}

`` `行く
wrap= errors.WrapfFunc "sの凊理に倱敗したした"、filename

f、err= os.Openfilename
trywraperr
f.Closeを延期する

info、err= f.Stat
trywraperr

Manual Pass-through, and Automatic Pass-through modes are also simple enough to be agreeable (despite often being a code smell):
```go
f, err := os.Open(filename)
if err != nil {
    return nil, err
}
defer f.Close()

info, err := f.Stat()
if err != nil {
    return nil, err
}
f := try(os.Open(filename))
defer f.Close()

info := try(f.Stat())

ただし、手動間接モヌドず自動間接モヌドはどちらも、埮劙な間違いの可胜性が高いため、どちらも非垞に䞍快です。

defer errd.Wrap(&err, "failed to do X for %s", filename)

var f *os.File
f, err = os.Open(filename)
if err != nil {
    return
}
defer f.Close()

var info os.FileInfo
info, err = f.Stat()
if err != nil {
    return
}
defer errd.Wrap(&err, "failed to do X for %s", filename)

f := try(os.Open(filename))
defer f.Close()

info := try(f.Stat())

繰り返しになりたすが、私はそれらを犁止しおいないこずは理解できたすが、間接モヌドを促進/祝犏するこずは、これがただ私にずっお明確な危険信号を䞊げおいるずころです。 十分に、珟時点では、私が前提党䜓に匷く懐疑的であり続けるために。

詊しおみおくださいそれを避けるための機胜であっおはなりたせん

info := try(try(os.Open(filename)).Stat())

ファむルリヌク。

぀たり、 tryステヌトメントは連鎖を蚱可したせん。 そしお、それはボヌナスずしお芋た目が良いです。 ただし、互換性の問題がありたす。

@sirkon tryは特別なので、 tryが関数のように芋えおも、それが重芁な堎合、蚀語はネストされたtryを蚱可しない可胜性がありたす。 繰り返しになりたすが、これがtryの唯䞀の障害である堎合、さたざたな方法 go vet 、たたは蚀語制限で簡単に察凊できたす。 これから先に進みたしょう-私たちは今䜕床もそれを聞いおいたす。 ありがずう。

これから先に進みたしょう-私たちは以前に䜕床もそれを聞いたこずがありたす

「これはずおも退屈です、これから先に進みたしょう」

別の良い類䌌物がありたす

-あなたの理論は事実ず矛盟しおいたす
-事実はもっず悪い

ヘヌゲル

私はあなたが実際には存圚しない問題を解決しおいるこずを意味したす。 そしお、その醜い方法。

この問題が実際に発生する堎所を芋おみたしょう。倖界からの副䜜甚の凊理、それだけです。 そしお、これは実際には゜フトりェア゚ンゞニアリングで論理的に最も簡単な郚分の1぀です。 そしお、その䞭で最も重芁です。 信頌性が䜎䞋する最も簡単なものを単玔化する必芁がある理由がわかりたせん。

IMOのこの皮の最も難しい問題は、分散システムでのデヌタの䞀貫性の維持です実際にはそれほど分散されおいたせん。 そしお、゚ラヌ凊理は、これらを解決するずきにGoで戊っおいた問題ではありたせんでした。 スラむスずマップの理解の欠劂、合蚈/代数/分散/その他のタむプの欠劂は、はるかに厄介でした。

ここでの議論は衰えるこずなく続いおいるように思われるので、もう䞀床繰り返したしょう。

経隓は、継続的な議論よりも䟡倀がありたす。 tryが自分のコヌドベヌスでどのように衚瀺されるかを実隓し、フィヌドバックペヌゞに゚クスペリ゚ンスレポヌトを䜜成しおリンクするこずをお勧めしたす。

具䜓的な経隓がこの提案に賛成たたは反察の重芁な蚌拠を提䟛する堎合は、ここでそれを聞きたいず思いたす。 個人的なペットのおしっこ、架空のシナリオ、代替デザむンなど、私たちは認めるこずができたすが、それらはあたり実甚的ではありたせん。

ありがずう。

私はここで倱瀌になりたくありたせん、そしおあなたのすべおの節床に感謝したす、しかしコミュニティぱラヌ凊理が倉曎されるこずに぀いお非垞に匷く話したした。 物事を倉曎したり、新しいコヌドを远加したりするず、珟圚のシステムを奜むすべおの人が動揺したす。 みんなを幞せにするこずはできないので、私たちが幞せにできる88に焊点を圓おたしょう以䞋の投祚率から導き出された数倀。

この蚘事の執筆時点では、「そのたたにしおおく」スレッドは、賛成1322祚、反察158祚です。 このスレッドは、䞊に158、䞋に255です。 それが゚ラヌ凊理に関するこのスレッドの盎接の終わりではない堎合は、問題をプッシュし続ける非垞に正圓な理由があるはずです。

あなたのコミュニティが叫ぶこずを垞に行い、同時にあなたの補品を砎壊するこずは可胜です。

少なくずも、この特定の提案は倱敗したず芋なされるべきだず思いたす。

幞い、 goは委員䌚による蚭蚈ではありたせん。 私たちは、私たち党員が愛する蚀語の管理者が、利甚可胜なすべおのデヌタを考慮しお最善の決定を䞋し続け、倧衆の䞀般的な意芋に基づいお決定を䞋さないこずを信頌する必芁がありたす。 芚えおおいおください-私たちず同じように、圌らもgoを䜿甚しおいたす。 圌らは私たちず同じように、問題点を感じたす。

あなたがポゞションを持っおいるなら、ゎヌチヌムが圌らの提案を守るのず同じようにそれを守るために時間をかけおください。 それ以倖の堎合は、実行可胜ではなく、䌚話を進めない倜間の感情で䌚話を溺れさせおいるだけです。 そしお、それは、人々がただ隒音が消えるたでそれを埅ちたいかもしれないず蚀ったように、埓事したい人々にずっおより難しくなりたす。

提案プロセスが開始されたずき、ラスは、提案に圱響を䞎えたり、あなたの芁求を聞いたりする方法ずしお、経隓報告の必芁性を広めるこずに぀いお倧したこずをしたした。 少なくずもそれを尊重しようずしたしょう。

goチヌムは、実甚的なフィヌドバックをすべお考慮に入れおいたす。 圌らはただ私たちを倱敗させおいたせん。 ゚むリアスやモゞュヌルなどに぀いお䜜成された詳现なドキュメントを参照しおください。少なくずも同じように考え、時間をかけお私たちの反察意芋を怜蚎し、反察意芋に察する圌らの立堎に察応し、反察意芋が無芖されにくくするようにしたしょう。

Goの利点は垞に、ポゞションにコミットする前にスペヌスを批刀的に考える少数の人々によっお蚭蚈された盎亀構造を持぀、小さくお単玔な蚀語であるずいうこずです。 「芋お、人気投祚はノヌず蚀う」ず蚀うのではなく、できる限り圌らを助けたしょう。投祚する倚くの人々は、行くこずや行くこずを完党に理解するこずさえあたり経隓しおいないかもしれたせん。 私は、この明らかに小さくお単玔な蚀語のいく぀かの基本的な抂念を知らないこずを認めたシリアルポスタヌを読みたした。 それはあなたのフィヌドバックを真剣に受け止めるのを難しくしたす。

ずにかく、私がここでこれを行っおいるのは残念です-このコメントを削陀しおください。 私は気分を害したせん。 しかし、誰かがこれを率盎に蚀わなければなりたせん

この2番目の提案党䜓は、私に集䌚を組織するデゞタルむンフル゚ンサヌず非垞によく䌌おいたす。 人気コンテストは技術的なメリットを評䟡したせん。

人々は沈黙しおいるかもしれたせんが、それでもGo2を期埅しおいたす。私は個人的にこれずGo2の残りの郚分を楜しみにしおいたす。Go1は玠晎らしい蚀語であり、さたざたな皮類のプログラムに適しおいたす。 Go2がそれを拡倧するこずを願っおいたす。

最埌に、ステヌトメントずしおtryを䜿甚するずいう私の奜みを逆にしたす。 今はそのたた提案を支持したす。 「Go1」コンパットの玄束の䞋で䜕幎も経った埌、人々はGoが石に刻たれたず思いたす。 その問題のある仮定のために、このむンスタンスで蚀語構文を倉曎しないこずは、今の私の目にははるかに良い劥協のように思えたす。 線集ファクトチェックのための゚クスペリ゚ンスレポヌトを芋るのも楜しみです。

PSゞェネリック医薬品が提案されるず、どのような反察が起こるのだろうか。

私たちの䌚瀟には、䞀気に曞かれた玄12のツヌルがありたす。 コヌドベヌスに察しおtryhardツヌルを実行し、933の朜圚的なtry候補を芋぀けたした。 個人的には、try関数は、コヌドの定型文の問題以䞊のものを解決するため、すばらしいアむデアだず思いたす。

呌び出し元ず呌び出された関数/メ゜ッドの䞡方に、最埌のパラメヌタヌずしお゚ラヌを返すように匷制したす。 これは蚱可されたせん

var file= try(parse())

func parse()(err, result) {
}

゚ラヌ倉数を宣蚀し、err= nil err == nilパタヌンを倧たかに蚱可する代わりに、゚ラヌを凊理する1぀の方法を匷制したす。これにより、読みやすさが劚げられ、IMOで゚ラヌが発生しやすいコヌドのリスクが高たりたす。

func Foo() (err error) {
    var file, ferr = os.Open("file1.txt")
    if ferr == nil {
               defer file.Close()
        var parsed, perr = parseFile(file)
        if perr != nil {
            return
        }
        fmt.Printf("%s", parsed)
    }
    return nil
}

tryを䜿甚するず、私の意芋では、コヌドはより読みやすく、䞀貫性があり、より安党になりたす。

func Foo() (err error) {
    var file = try(os.Open("file.txt"))
        defer file.Close()
    var parsed = try(parseFile(file))
    fmt.Printf(parsed)
    return
}

@lparがHerokuのアヌカむブされおいないすべおのGoリポゞトリパブリックおよびプラむベヌトで実行したのず同様の実隓をいく぀か実行したした。

結果はこの芁点にありたす https //gist.github.com/freeformz/55abbe5da61a28ab94dbb662bfc7f763

cc @davecheney

@ubikenobiあなたのより安党な機胜が挏れおいたした。

たた、゚ラヌの埌に倀が返されるのを芋たこずがありたせん。 ただし、関数がすべお゚ラヌに関するものであり、返される他の倀が゚ラヌ自䜓に䟝存しない堎合は、理にかなっおいるず想像できたす2番目の゚ラヌが前の倀を「保護」しお2回返される可胜性がありたす。

最埌に、䞀般的ではありたせんが、 err == nilは、いく぀かの早期返品の正圓なテストを提䟛したす。

@Daved

リヌクに぀いお指摘しおくれおありがずう、䞡方の䟋にdefer.Closeを远加するのを忘れたした。 今すぐ曎新。

errがこの順序で返されるこずはめったにありたせんが、蚭蚈よりも間違いである堎合は、コンパむル時にそれらをキャッチできるのは良いこずです。

ほずんどの堎合、err == nilの堎合は暙準よりも䟋倖だず思いたす。 あなたが蚀ったようにそれはいく぀かの堎合に圹立぀かもしれたせんが、私が奜きではないのは、開発者が正圓な理由なしに䞀貫性のない遞択をしおいるこずです。 幞い、コヌドベヌスでは、ステヌトメントの倧郚分がerr= nilであり、try関数の恩恵を受けるこずができたす。

  • 私は、他の4人の゚ンゞニアのチヌムでフルタむムで維持しおいる倧芏暡なGoAPIに察しおtryhardを実行したした。 45580行のGoコヌドで、 tryhardは曞き換える301゚ラヌを識別したした぀たり、+ 301 / -903の倉曎になりたす。たたは、各゚ラヌに玄3行かかるず仮定するず、コヌドの玄2が曞き換えられたす。 コメント、空癜、むンポヌトなどを考慮に入れるず、私にずっお重芁だず感じたす。
  • 私はtryhardのラむンツヌルを䜿甚しお、 tryが私の䜜業をどのように倉えるかを調査しおきたしたが、䞻芳的には非垞にうたく流れたす。 動詞tryは、呌び出し元の関数で問題が発生する可胜性があるこずをより明確に感じ、コンパクトに実行したす。 私はif err != nilを曞くこずに非垞に慣れおいお、本圓に気にしたせんが、倉曎しおもかたいたせん。 ゚ラヌの前に空の倉数を曞き蟌んでリファクタリングする぀たり、空のスラむス/マップ/倉数を返すようにするこずは、おそらくerr自䜓よりも面倒です。
  • 議論のすべおのスレッドをたどるのは少し難しいですが、これが゚ラヌをラップするために䜕を意味するのか興味がありたす。 オプションでtry(json.Unmarshal(b, &accountBalance), "failed to decode bank account info for user %s", user)のようなコンテキストを远加したい堎合は、 tryが可倉個匕数であるず䟿利です。 線集この点はおそらくトピックから倖れおいたす。 ただし、詊行しない曞き換えを芋るず、これが発生したす。
  • 私はこれに泚がれおいる考えず泚意に本圓に感謝しおいたす 䞋䜍互換性ず安定性は私たちにずっお非垞に重芁であり、これたでのGo 2の取り組みは、プロゞェクトを維持するために非垞にスムヌズでした。 ありがずう

これは、亀換が合理的であるこずを確認するために、経隓豊富なGopherによっお粟査された゜ヌスで行われるべきではありたせんか その「2」の曞き換えのうち、明瀺的な凊理で曞き換えるべきだったのはどれくらいですか それがわからない堎合、LOCは比范的圹に立たないメトリックのたたです。

*これが、今朝の私の投皿が゚ラヌ凊理の「モヌド」に焊点を圓おた理由です。 tryが容易にする゚ラヌ凊理のモヌドに぀いお説明し、それから、かなり任意のラむンカりンタヌを実行するよりも、䜜成する可胜性のあるコヌドの朜圚的な危険性に取り組む方が簡単で実質的です。

@kingishbメむン以倖のパッケヌゞのパブリック関数で芋぀かった_try_スポットはいく぀ありたすか 通垞、パブリック関数はパッケヌゞネむティブ぀たり、ラップたたは装食された゚ラヌを返す必芁がありたす。

@networkimprovそれは私の感性のための過床に単玔化された匏です。 それが真実であるのは、怜査可胜な゚ラヌを返すAPIサヌフェスの芳点からです。 通垞は、コヌルスタック内の䜍眮ではなく、コンテキストの関連性に基づいお゚ラヌメッセヌゞにコンテキストを远加するのが適切です。

珟圚の指暙では、倚くの誀怜知が発生しおいる可胜性がありたす。 たた、掚奚される方法https://blog.golang.org/errors-are-valuesに埓うこずで発生するミスに぀いおはどうでしょうか。 tryは、そのようなプラクティスの䜿甚を枛らす可胜性があり、その意味で、それらは眮き換えの䞻芁なタヌゲットですおそらく、私が本圓に興味を持っおいる唯䞀のナヌスケヌスの1぀です。 したがっお、繰り返しになりたすが、これは、デュヌデリゞェンスを倧幅に行わずに既存の゜ヌスをスクレむプするこずは無意味に思えたす。

デヌタを収集しおくれた@ ubikenobi 、@ freeformz、 @ kingishbに感謝したす 䜙談ですが、オプション-err="" $を指定しおtryhardを実行するず、゚ラヌ倉数がerr以倖の名前 eなどで呌び出されるコヌドも凊理しようずしたす。

より倚くのデヌタポむントを探しおいる堎合は、 @ griesemer 。 2぀のマむクロサヌビスに察しおtryhardを実行したずころ、次の結果が埗られたした。

cloc v 1.82 / tryhard
13280Goコヌド行/ 148詊行甚に識別1

別のサヌビス
9768Goコヌド行/詊行甚に識別された500.5

その埌、 tryhardは、さたざたなマむクロサヌビスの幅広いセットを怜査したした。

314343Goコヌド行/ 1563詊行甚に識別0.5

迅速な怜査を行いたす。 tryが最適化できるパッケヌゞのタむプは、通垞、ラップされたサヌビスから返されたGRPC゚ラヌを透過的に返すアダプタヌ/サヌビスラッパヌです。

お圹に立おれば。

それは絶察に悪い考えです。

  • deferのerr varはい぀衚瀺されたすか 「暗黙的よりも明瀺的」はどうですか
  • 単玔なルヌルを䜿甚したす。゚ラヌが返された堎所を1぀だけすばやく芋぀ける必芁がありたす。 すべおの゚ラヌは、䜕がどこでうたくいかないかを理解するためにコンテキストでラップされたす。 deferは、倚くの醜くお理解しにくいコヌドを䜜成したす。
  • @davecheneyぱラヌに぀いお玠晎らしい投皿を曞き、提案はこの投皿のすべおに完党に反察しおいたす。
  • 最埌に、 os.Exitを䜿甚するず、゚ラヌのチェックが倖されたす。

パッケヌゞベンダヌを䜿甚でtryhardを実行したずころ、コヌド数が873934から851178に枛少した2478が報告されたしたが、よくわかりたせんそれをどのように解釈するかは、オヌバヌラッピングstdlibがスタックトレヌス゚ラヌラッピングのサポヌトを欠いおいるによるものか、そのコヌドのどれだけが゚ラヌ凊理に関するものかわからないためです。

しかし、私が知っおいるのは、今週だけでも、 if err != nil { return nil }のようなコピヌパスタずerror: cannot process ....file: cannot parse ...file: cannot open ...fileのような゚ラヌのために、恥ずかしい時間を無駄にしたずいうこずです。

\ そこにGo開発者が3000人しかいないず思わない限り、投祚数をあたり重芖したせん。 他の非提案に察する高い投祚数は、問題がHNずRedditのトップに到達したずいう事実によるものです。Goコミュニティは、教矩の欠劂や吊定的な発蚀で正確に知られおいたせん。 -投祚数に驚かされるはずです。

たた、圓局ぞの蚎えの詊みも真剣に受け止めたせん。なぜなら、これらの同じ圓局は、圌ら自身の無知や誀解が指摘された埌でも、新しいアむデアや提案を拒吊するこずが知られおいるからです。
\

最倧のテストを含む±163k行のコヌドサヌビスでtryhard -err=""を実行したした-566回の発生が芋぀かりたした。 䞀郚のコヌドはif err != nilを念頭に眮いお蚘述されおいるため、実際にはさらに倚くなるず思いたす。そのため、コヌドはそれを䞭心に蚭蚈されおいたすRob Pikeの繰り返しの回避に関する「゚ラヌは䟡倀芳」の蚘事が思い浮かびたす。

@griesemer芁点に新しいファむルを远加したした。 -err = ""で生成されたした。 スポットチェックを行いたしたが、いく぀か倉曎がありたす。 今朝もtryhardをアップデヌトしたので、新しいバヌゞョンも䜿甚したした。

@griesemer集蚈できれば、tryhardの方が䟿利だず思いたす。

a゚ラヌが発生したコヌルサむトの数
bシングルステヌトメントif err != nil [&& ...]ハンドラヌの数 on err 32611の候補
c䜕かを返すものの数 defer 32676の候補
d errを返すものの数 try()の候補
e非メむンパッケヌゞの゚クスポヌトされた機胜に含たれるものの数誀怜知の可胜性が高い

合蚈LoCをreturn errのむンスタンスず比范するず、コンテキストが䞍足しおいたす、IMO。

@networkimprov同意したした-同様の提案が以前に提起されたした。 これを改善するために、今埌数日間で時間を芋぀けようず思いたす。

内郚コヌドベヌス䟝存関係ではなく、コヌドのみに察しおtryhardを実行した堎合の統蚈は次のずおりです。

前

  • 882.goファむル
  • 352434 loc
  • 329909空でない堎所

詊しおみた埌

  • 2701眮換平均3.1眮換/ファむル
  • 345364 loc-2.0
  • 322838空でない堎所-2.1

線集 @griesemerが芁玄統蚈量を含むようにtryhardを曎新したので、ここにさらにいく぀かありたす

  • if if <err> != nilです
  • これらの69.6はtry候補です

tryhardが芋぀けた眮換を芋るず、 tryの䜿甚が非垞に䞀般的であるタむプのコヌドず、めったに䜿甚されないタむプのコヌドが確かにありたす。

たた、tryhardが倉換できない堎所もありたすが、tryの恩恵を受けるこずができたす。 たずえば、単玔なワむダヌプロトコル単玔さ/明確さのために線集に埓っおメッセヌゞをデコヌドするためのコヌドを次に瀺したす。

func (req *Request) Decode(r Reader) error {
    typ, err := readByte(r)
    if err != nil {
        return err
    }
    req.Type = typ
    req.Body, err = readString(r)
    if err != nil {
        return unexpected(err)
    }

    req.ID, err = readID(r)
    if err != nil {
        return unexpected(err)
    }
    n, err := binary.ReadUvarint(r)
    if err != nil {
        return unexpected(err)
    }
    req.SubIDs = make([]ID, n)
    for i := range req.SubIDs {
        req.SubIDs[i], err = readID(r)
        if err != nil {
            return unexpected(err)
        }
    }
    return nil
}

// unexpected turns any io.EOF into an io.ErrUnexpectedEOF.
func unexpected(err error) error {
    if err == io.EOF {
        return io.ErrUnexpectedEOF
    }
    return err
}

tryがない堎合、1か所で凊理しおも倧きな改善はないため、必芁なリタヌンポむントにunexpectedを曞き蟌んだだけです。 ただし、 tryを䜿甚するず、 unexpected゚ラヌ倉換を延期しお適甚し、コヌドを倧幅に短瞮しお、より明確で簡単にスキミングできたす。

func (req *Request) Decode(r Reader) (err error) {
    defer func() { err = unexpected(err) }()

    req.Type = try(readByte(r))
    req.Body = try(readString(r))
    req.ID = try(readID(r))

    n := try(binary.ReadUvarint(r))
    req.SubIDs = make([]ID, n)
    for i := range req.SubIDs {
        req.SubIDs[i] = try(readID(r))
    }
    return nil
}

@cespare玠晎らしいレポヌト

完党に瞮小されたスニペットの方が䞀般的に優れおいたすが、括匧は予想よりもさらに悪く、ルヌプ内のtryは予想どおりに悪くなっおいたす。

キヌワヌドははるかに読みやすく、他の倚くの人が異なる点であるずいうのは少し非珟実的です。 以䞋は読みやすく、返される倀が1぀だけであるため、埮劙な点に぀いお心配する必芁はありたせんただし、より長い関数やネストの倚い関数では、それでも発生する可胜性がありたす。

func (req *Request) Decode(r Reader) (err error) {
    defer func() { err = wrapEOF(err) }()

    req.Type = try readByte(r)
    req.Body = try readString(r)
    req.ID = try readID(r)

    n := try binary.ReadUvarint(r)
    req.SubIDs = make([]ID, n)
    for i := range req.SubIDs {
        req.SubIDs[i], err = readID(r)
        try err
    }
    return nil
}

*公平を期すず、コヌドの匷調衚瀺は倧いに圹立ちたすが、それは安い口玅のようです。

あなたは本圓に悪いコヌドの堎合にあなたが埗る最倧の利点を理解しおいたすか

unexpected()を䜿甚するか、゚ラヌをそのたた返す堎合、コヌドずアプリケヌションに぀いお䜕も知りたせん。

tryは、より良いコヌドを曞くのに圹立ちたせんが、より悪いコヌドを生成する可胜性がありたす。

@cespareデコヌダヌは、゚ラヌタむプが内郚にある構造䜓にするこずもできたす。メ゜ッドは、すべおの操䜜の前にerr == nilをチェックし、ブヌル倀のokを返したす。

これはコヌデックに䜿甚するプロセスであるため、 tryは、この特定のケヌスの゚ラヌを凊理するための非魔法的で短く、より簡朔なむディオムを簡単に䜜成できるため、たったく圹に立ちたせん。

@makhov 「本圓に悪いコヌド」ずは、゚ラヌをラップしないコヌドを意味するず思いたす。

もしそうなら、あなたはこのようなコヌドを取るこずができたす

a, b, c, err := someFn()
if err != nil {
  return ..., errors.Wrap(err, ...)
}

そしお、それを次のような意味的に同䞀の[1]コヌド​​に倉換したす。

a, b, c, err := someFn()
try(errors.Wrap(err, ...))

提案では、゚ラヌの折り返しにdeferを䜿甚する必芁があるずは蚀っおおらず、蚀語を倉曎せずにdeferの芳点から実装できるため、提案の前の反埩のhandleキヌワヌドが䞍芁である理由を説明しおいるだけです。

あなたの他のコメントも、提案されおいるものの栞心ではなく、提案の䟋たたは擬䌌コヌドに基づいおいるようです

コヌドベヌスで54KLOCを䜿甚しおtryhardを実行したしたが、1116個のむンスタンスが芋぀かりたした。
私はdiffを芋たしたが、 if err != nilタむプの構成のほずんどすべおの䜿甚は、単玔な単䞀レベルのブロックであり、远加されたコンテキストで゚ラヌが発生したした。 tryが実際にコヌドの構成を倉曎するむンスタンスをいく぀か芋぀けただけだず思いたす。

蚀い換えれば、私の芋解は、珟圚の圢匏のtryが私に䞎えるずいうこずです

  • タむピングが少なくなりたす以䞋の「**」で瀺される、発生ごずに最倧30文字の削枛
-       **if err := **json.NewEncoder(&buf).Encode(in)**; err != nil {**
-               **return err**
-       **}**
+       try(json.NewEncoder(&buf).Encode(in))

それは私にこれらの問題をもたらしたすが

  • ゚ラヌを凊理するさらに別の方法
  • 実行パス分割の芖芚的な手がかりがありたせん

このスレッドで前に曞いたように、私はtryで生掻できたすが、コヌドで詊しおみた埌、個人的にはこれを蚀語に導入したくないず思いたす。 私の$ .02

圹に立たない機胜、タむピングを節玄したすが、倧したこずではありたせん。
私はむしろ叀い方法を遞びたす。
より倚くの゚ラヌハンドラを䜜成しお、トラブルシュヌティングを容易にするプログラムを䜜成したす。

ちょっず考えお...

そのむディオムはgoで圹立ちたすが、それはたさにそれですあなたがしなければならないむディオム
新芏参入者に教える。 新しいgoプログラマヌはそれを孊ぶ必芁がありたす。
「隠された」゚ラヌ凊理をリファクタリングしたくなるかもしれたせん。 たた、
忘れない限り、そのむディオムを䜿甚しおコヌドを短くするこずはできたせんたったく逆です。
メ゜ッドを数えたす。

ここで、tryが実装されおいるず想像しおみたしょう。そのむディオムは、どの皋床圹立぀のでしょうか。
そのナヌスケヌス 考慮事項

  • メ゜ッド間で分散するのではなく、実装をより緊密に保぀ようにしおください。
  • プログラマヌは、それよりもはるかに頻繁にコヌドを読み曞きしたす
    特定のむディオムすべおの特定のタスクを陀いおほずんど䜿甚されたせん。 A
    明確なものがない限り、より䜿甚されるむディオムはより自然で読みやすくなりたす
    䞍利な点。これは、䞡方を
    心を開いおください。

したがっお、そのむディオムは、tryに取っお代わられたず芋なされる可胜性がありたす。

Em ter、2019幎7月2日1806、 notifications @ github.com escreveuずしお

@cespare https://github.com/cespareデコヌダヌは、次の構造䜓にするこずもできたす
その䞭の゚ラヌタむプ。メ゜ッドは前にerr == nilをチェックしたす。
すべおの操䜜ずブヌル倀のOKを返したす。

これはコヌデックに䜿甚するプロセスであるため、tryはたったく圹に立ちたせん
なぜなら、魔法ではなく、短く、より簡朔なむディオムを簡単に䜜成できるからです。
この特定のケヌスの゚ラヌを凊理するため。

—
あなたが蚀及されたので、あなたはこれを受け取っおいたす。
このメヌルに盎接返信し、GitHubで衚瀺しおください
https://github.com/golang/go/issues/32437?email_source=notifications&email_token=AAT5WM3YDDRZXVXOLDQXKH3P5O7L5A5CNFSM4HTGCZ72YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW
たたはスレッドをミュヌトしたす
https://github.com/notifications/unsubscribe-auth/AAT5WMYXLLO74CIM6H4Y2RLP5O7L5ANCNFSM4HTGCZ7Q
。

私の意芋では、゚ラヌ凊理の冗長性は良いこずです。 蚀い換えれば、私は詊しおみるための匷力なナヌスケヌスを芋おいたせん。

私はこの考えを受け入れおいたすが、実行分割が発生した堎所を刀別するための䜕らかのメカニズムを含める必芁があるず感じおいたす。 Xerror / Isは、堎合によっおは問題ありたせんがたずえば、゚ラヌがErrNotExistsの堎合、Openで発生したず掚枬できたす、ラむブラリのレガシヌ゚ラヌを含む他の堎合には代替手段がありたせん。

制埡フロヌが倉曎された堎所に関するコンテキスト情報を提䟛するために、recoverず同様の組み蟌みを含めるこずができたすか おそらく、それを安く保぀ために、tryの代わりに別の関数が䜿甚されたす。

たたは、おそらくデバッグです。tryず同じ構文で、デバッグ情報を远加しお詊しおください。 このように、tryは、叀い゚ラヌ凊理に頌るこずなく、叀い゚ラヌを䜿甚するコヌドでも同様に圹立ちたす。

別の方法は、tryでコンテキストをラップしお远加するこずですが、ほずんどの堎合、これは目的のないパフォヌマンスを䜎䞋させるため、远加の関数を提案したす。

線集これを曞いた埌、コンパむラヌは、deferステヌトメントが「recover」ず同様のこのコンテキスト提䟛関数を䜿甚するかどうかに基づいお、䜿甚するtryのバリアントを決定できるこずに気付きたした。 ただし、これの耇雑さに぀いおは定かではありたせん

@lestrratこのコメントでは私の意芋は蚀いたせんが、「try」が私たちにどのように圱響するかを説明する機䌚があれば、ifステヌトメントに2぀以䞊のトヌクンを曞き蟌むこずができたす。 したがっお、ifステヌトメントに200の条件を蚘述するず、倚くの行を枛らすこずができたす。

if try(foo()) == 1 && try(bar()) == 2 {
  // err
}
n1, err := foo()
if err != nil {
  // err
}
n2, err := bar()
if err != nil {
  // err
}
if n1 == 1 && n2 == 2 {
  // err
}

@mattnはそれですが、_理論的には_あなたは絶察に正しいです。 tryがぎったり合うケヌスを思い぀くこずができるず確信しおいたす。

私は、実際には、少なくずも_I_が、_mycode_で詊行するための翻蚳の恩恵を受けるような構造の発生をほずんど怜出しなかったデヌタを提䟛したした。

私が他の䞖界ずは異なる方法でコヌドを曞くこずは可胜ですが、PoCの翻蚳に基づいお、誰かがチャむムを鳎らす䟡倀があるず思ったのですが、 tryの導入から実際に倚くを埗るこずができない人もいたす。蚀語に

䜙談ですが、コヌドではただあなたのスタむルを䜿甚したせん。 私はそれを次のように曞きたす

n1 := try(foo())
n2 := try(bar())
if n1 == 1 && n2 == 2 {
   return errors.New(`boo`)
}

したがっお、これらのn1 / n2 / .... nnのむンスタンスごずにほが同じ量の入力を節玄できたす。

なぜキヌワヌドたたは関数があるのですか

呌び出し元のコンテキストがn + 1の倀を期埅しおいる堎合、すべおが以前ず同じです。

呌び出し元のコンテキストがn個の倀を予期しおいる堎合、try動䜜が開始されたす。

これは、すべおのひどい混乱が発生するn = 1の堎合に特に圹立ちたす。

私のideはすでに無芖された戻り倀を匷調しおいたす。 必芁に応じお、このための芖芚的な手がかりを提䟛するのは簡単です。

@balasanjayはい、ラッピング゚ラヌが発生したす。 しかし、ロギング、さたざたな゚ラヌに察するさたざたな反応 sql.NoRowsなどの゚ラヌ倉数で䜕をすべきか、読み取り可胜なコヌドなどもありたす。 読者にわかりやすくするために、ファむルを開いた盎埌にdefer f.Close()ず曞き蟌みたす。 同じ理由ですぐに゚ラヌをチェックしたす。

最も重芁なこずは、この提案が「゚ラヌは倀である」ずいうルヌルに違反しおいるこずです。 これがGoの蚭蚈方法です。 そしお、この提案は芏則に盎接反したす。

try(errors.Wrap(err, ...))は、この提案ず珟圚のGo蚭蚈の䞡方ず矛盟するため、別のひどいコヌドです。

私は@lestrratに同意する傟向がありたす
通垞、fooずbarは実際には次のずおりです。
SomeFunctionWithGoodNameParm1、Parms2

その堎合、提案される@mattn構文は実際には次のようになりたす。

if  try(SomeFunctionWithGoodName(Parm1, Parms2)) == 1 && try(package.SomeOtherFunction(Parm1, Parms2,Parm3))) == 2 {


} 

読みやすさは通垞混乱したす。

戻り倀を怜蚎したす。
someRetVal, err := SomeFunctionWithGoodName(Parm1, Parms2)
1や2などの定数ず比范するよりも頻繁に䜿甚されおおり、悪化するこずはありたせんが、二重代入機胜が必芁です。

if  a := try(SomeFunctionWithGoodName(Parm1, Parms2)) && b:= try(package.SomeOtherFunction(Parm1, Parms2,Parm3))) {


} 

すべおのナヌスケヌスに぀いお「tryhardはどれだけ私を助けおくれたしたか」

  1. ラむブラリず実行可胜ファむルの間に倧きな違いが芋られるず思いたす。他の人からもこの違いが埗られるかどうかを確認するのは興味深いこずです。
  2. 私の提案は、コヌド内の行のsaveではなく、コヌド内の゚ラヌの数ずリファクタリングされた数を比范するこずです。
    これに察する私の芋解は
    $find /path/to/repo -name '*.go' -exec cat {} \; | grep "err :=" | wc -l
    。

@makhov

この提案は「゚ラヌは䟡倀芳である」ずいうルヌルに違反しおいたす

あたり。 この提案では、゚ラヌは䟝然ずしお倀です。 try()は、 if err != nil { return ...,err }のショヌトカットになるこずで、制埡フロヌを単玔化しおいたす。 error型は、組み蟌みのむンタヌフェむス型であるため、すでに䜕らかの圢で「特別」です。 この提案は、 errorタむプを補完する組み蟌み関数を远加するだけです。 ここに特別なこずは䜕もありたせん。

@ngrilly単玔化 どのように

func (req *Request) Decode(r Reader) error {
    defer func() { err = unexpected(err) }()

    req.Type = try(readByte(r))
    req.Body = try(readString(r))
    req.ID = try(readID(r))

    n := try(binary.ReadUvarint(r))
    req.SubIDs = make([]ID, n)
    for i := range req.SubIDs {
        req.SubIDs[i] = try(readID(r))
    }
    return nil
}

゚ラヌがルヌプ内で返されたこずをどのように理解する必芁がありたすか fooではなくerr varに割り圓おられるのはなぜですか
それを芚えお、コヌドに入れないほうが簡単ですか

@daved

括匧は私が予想しおいたよりもさらに悪いです[...]キヌワヌドははるかに読みやすく、それが他の倚くの人が異なる点であるずいうのは少し非珟実的です。

キヌワヌドず組み蟌み関数のどちらを遞択するかは、䞻に矎的および構文䞊の問題です。 なぜこれがあなたの目にずおも重芁なのか私は正盎に理解しおいたせん。

PS組み蟌み関数には、䞋䜍互換性があり、将来的に他のパラメヌタヌで拡匵可胜であり、挔算子の優先順䜍に関する問題を回避できるずいう利点がありたす。 キヌワヌドには...キヌワヌドであるずいう利点があり、 tryのシグナリングは「特別」です。

@makhov

単玔化

Ok。 正しい蚀葉は「短瞮」です。

try()は、パタヌンif err != nil { return ..., err }を組み蟌みのtry()関数の呌び出しに眮き換えるこずで、コヌドを短瞮したす。

これは、コヌドで繰り返しパタヌンを識別し、それを新しい関数で抜出する堎合ずたったく同じです。

スラむスに䜕かを远加する必芁があるたびに自分でコヌドを「extenso」で蚘述するこずで眮き換えるこずができるappendのような組み蟌み関数がすでにありたす。 しかし、私たちは垞にそれを行っおいるので、それは蚀語に統合されたした。 try()も同じです。

゚ラヌがルヌプ内で返されたこずをどのように理解する必芁がありたすか

ルヌプ内のtry()は、ルヌプ倖の残りの関数のtry()ずたったく同じように機胜したす。 readID()が゚ラヌを返す堎合、関数ぱラヌを返したすifを装食した埌。

なぜそれがfooではなくerrvarに割り圓おられおいるのですか

コヌド䟋にfoo倉数が衚瀺されたせん...

@makhov返された゚ラヌに名前が付けられおいないため、スニペットは䞍完党だず思いたす提案をすばやく読み盎したしたが、倉数名errが蚭定されおいない堎合、デフォルト名であるかどうかを確認できたせんでした。

返されたパラメヌタの名前を倉曎しなければならないこずは、この提案を拒吊する人々が気に入らない点の1぀です。

func (req *Request) Decode(r Reader) (err error) {
    defer func() { err = unexpected(err) }()

    req.Type = try(readByte(r))
    req.Body = try(readString(r))
    req.ID = try(readID(r))

    n := try(binary.ReadUvarint(r))
    req.SubIDs = make([]ID, n)
    for i := range req.SubIDs {
        req.SubIDs[i] = try(readID(r))
    }
    return nil
}

@pierrec名前付きパラメヌタヌにない堎合は、 recover()のような関数を䜿甚しお゚ラヌを取埗できたすか
defer func() {err = unexpected(tryError())}

@makhovあなたはそれをより明確にするこずができたす

func (req *Request) Decode(r Reader) error {
    req.Type, err := readByte(r)
        try(err) // or add annotation like try(annotate(err, ...))
    req.Body, err := readString(r)
        try(err)
    req.ID, err := readID(r)
        try(err)

    n, err := binary.ReadUvarint(r)
        try(err)
    req.SubIDs = make([]ID, n)
    for i := range req.SubIDs {
        req.SubIDs[i], err := readID(r)
                try(err)
    }
    return nil
}

@pierrecわかりたした、倉曎したしょう

func (req *Request) Decode(r Reader) error {
        var errOne, errTwo error
    defer func() { err = unexpected(???) }()

    req.Type = try(readByte(r))
    

}

@reuseeそしお、なぜこれよりも優れおいるのですか

func (req *Request) Decode(r Reader) error {
    req.Type, err := readByte(r)
        if err != nil { return err }
        

}

読みやすさよりも短さの方が優れおいるず私たち党員が刀断したのはい぀ですか。

@flibustenet問題を理解しおいただきありがずうございたす。 芋た目ははるかに良くなりたすが、この小さな「改善」のために䞋䜍互換性を壊す必芁があるかどうかはただわかりたせん。 新しいバヌゞョンのGoでビルドを停止するアプリケヌションがあるず、非垞に煩わしくなりたす。

package main

func main() {
    // ...
   try("a", "b")
    // ...
}

func try(a, b string) {
    // ...
}

@makhovこれを明確にする必芁があるこずに同意したす。倉数を理解できない堎合、コンパむラぱラヌになりたすか そうだず思いたした。
たぶん、提案はこの点を明確にする必芁がありたすか それずも私はそれを文曞で芋逃したしたか

@flibustenetはい、これはtryを䜿甚する1぀の方法ですが、tryを䜿甚する慣甚的な方法ではないように思われたす。

@cespareあなたが曞いたこずから、deferの戻り倀の倉曎はtryの機胜のようですが、すでにこれを行うこずができたす。

https://play.golang.com/p/ZMauFmt9ezJ

あなたの蚀ったこずを誀解しおすみたせん

@ jan-g https://github.com/golang/go/issues/32437#issuecomment -507961463に぀いお目に芋えない圢で゚ラヌを凊理するずいう考えが䜕床も出おきたした。 このような暗黙的なアプロヌチの問題は、呌び出された関数に゚ラヌリタヌンを远加するず、呌び出し元の関数がサむレントに、目に芋えない圢で異なる動䜜をする可胜性があるこずです。 ゚ラヌがチェックされるずきは、絶察に明瀺的にしたいず思いたす。 暗黙のアプロヌチは、すべおが明瀺的であるずいうGoの䞀般原則にも反したす。

@griesemer

プロゞェクトの1぀https://github.com/komuw/meliでtryhandを詊したしたが、倉曎はありたせんでした。

gobin github.com/griesemer/tryhard
     Installed github.com/griesemer/[email protected] to ~/go/bin/tryhard

`` `bash
〜/ go / bin / tryhard -err "" -r
0

most of my err handling looks like;
```Go
import "github.com/pkg/errors"

func CreateDockerVolume(volName string) (string, error) {
    volume, err := VolumeCreate(volName)
    if err != nil {
        return "", errors.Wrapf(err, "unable to create docker volume %v", volName)
    }
    return volume.Name, nil
}

@komuwたず、ファむル名たたはディレクトリの匕数をtryhardに指定しおください。

tryhard -err="" -r .  // <<< note the dot
tryhard -err="" -r filename

たた、コメントにあるようなコヌドは、 ifブロックで特定の゚ラヌ凊理を行うため、曞き盎されたせん。 適甚される時期に぀いおは、 tryhardのドキュメントをお読みください。 ありがずう。

func CreateDockerVolume(volName string) (string, error) {
    volume, err := VolumeCreate(volName)
    if err != nil {
        return "", errors.Wrapf(err, "unable to create docker volume %v", volName)
    }
    return volume.Name, nil
}

これはやや興味深い䟋です。 それを芋たずきの私の最初の反応は、これが次のような吃音の゚ラヌ文字列を生成するかどうかを尋ねるこずでした。

unable to create docker volume: VolumeName: could not create volume VolumeName: actual problem

VolumeCreate関数別のリポゞトリからは次のずおりであるため、答えはそうではありたせん。

func (cli *Client) VolumeCreate(ctx context.Context, options volumetypes.VolumeCreateBody) (types.Volume, error) {
        var volume types.Volume
        resp, err := cli.post(ctx, "/volumes/create", nil, options, nil)
        defer ensureReaderClosed(resp)
        if err != nil {
                return volume, err
        }
        err = json.NewDecoder(resp.body).Decode(&volume)
        return volume, err
}

぀たり、基になる関数が゚ラヌを装食しなかったため、゚ラヌの远加の装食が圹立ちたす。 その基瀎ずなる関数は、 tryで少し簡略化できたす。

おそらく、 VolumeCreate関数は実際にその゚ラヌを装食しおいるはずです。 ただし、その堎合、提䟛する新しい情報がないため、 CreateDockerVolume関数で装食を远加する必芁があるかどうかはわかりたせん。

@neild
VolumeCreateが゚ラヌを装食する堎合でも、他のさたざたな関数からVolumeCreateが呌び出される可胜性があるため、装食を远加するにCreateDockerVolumeが必芁です。ログに蚘録された䜕が倱敗したかを知りたい-この堎合はCreateDockerVolume 、
それでも、 VolumeCreateを怜蚎するこずはAPIclientむンタヌフェヌスの䞀郚です。

同じこずが他のラむブラリにも圓おはたりたす- os.Openはファむル名、゚ラヌの理由などをうたく食るこずができたすが、
func ReadConfigFile(...
func WriteDataFile(...
など- os.Openの呌び出しは、゚ラヌをログに蚘録、トレヌス、および凊理するために確認したい実際の障害郚分です。特に、本番環境だけではありたせん。

@neildありがずう。

このスレッドを脱線させたくないのですが...

おそらく、VolumeCreate関数は実際にその゚ラヌを装食しおいるはずです。
ただし、その堎合、
CreateDockerVolume関数
远加の装食を远加する必芁がありたす、

問題は、 CreateDockerVolume関数の䜜成者ずしお、私はそうではないかもしれないずいうこずです
VolumeCreateの䜜者が゚ラヌを装食したかどうかを知っおいるので、私は
私を食る必芁はありたせん。
そしお、私が圌らが持っおいるこずを知っおいたずしおも、圌らは圌らの装食を倖すこずを決めるこずができたした
それ以降のバヌゞョンで機胜したす。 そしお、その倉曎はAPIを倉曎するものではないため、
パッチ/マむナヌバヌゞョンずしおリリヌスし、今では私の機胜は
装食された゚ラヌを持っおいるそれらの機胜に䟝存しお、すべおを持っおいるわけではありたせん
必芁な情報。
だから䞀般的に私は自分が図曞通だずしおも食ったりラッピングしたりしおいるこずに気付く
呌び出しはすでに終了しおいたす。

同僚ずtryに぀いお話しおいるずきに考えたした。 たぶんtryは1.14の暙準ラむブラリに察しおのみ有効にする必芁がありたす。 @crawshawず@jimmyfrascheはどちらも、いく぀かのケヌスを簡単に説明し、いく぀かの芖点を瀺したしたが、実際には、可胜な限りtryを䜿甚しお暙準ラむブラリコヌドを曞き盎すこずは䟡倀がありたす。

これにより、Goチヌムはそれを䜿甚しお重芁なプロゞェクトを曞き盎す時間ができ、コミュニティはそれがどのように機胜するかに぀いおの経隓レポヌトを持぀こずができたす。 䜿甚頻床、 deferずペアリングする必芁がある頻床、コヌドの可読性が倉わる堎合、 tryhardの有甚性などがわかりたす。

これは暙準ラむブラリの粟神に少し反しおおり、通垞のGoコヌドでは䜿甚できないものを䜿甚できたすが、 tryが既存のコヌドベヌスにどのように圱響するかを確認するための遊び堎を提䟛したす。

他の誰かがこれに぀いおすでに考えおいる堎合はお詫びしたす。 いろいろな議論をしたしたが、䌌たような提案は芋圓たりたせんでした。

@jonbodner https://go-review.googlesource.com/c/go/+/182717は、それがどのように芋えるかに぀いおのかなり良いアむデアを提䟛したす。

そしお、私は蚀うのを忘れたした私はあなたの調査に参加したした、そしお私はこれではなく、より良い゚ラヌ凊理に投祚したした。

゚ラヌ凊理を忘れないようにもっず厳しくしたいずいう意味でした。

@jonbodner https://go-review.googlesource.com/c/go/+/182717は、それがどのように芋えるかに぀いおのかなり良いアむデアを提䟛したす。

総括する

  1. 1行が4行を普遍的に眮き換えたす if ... { return err }を䜿甚する堎合は2行
  2. ただし、返された結果の評䟡は、フェむルパスでのみ最適化できたす。

芋た目の倉曎のように芋えるものの合蚈で玄6,000の亀換既存の゚ラヌを公開せず、おそらく新しい゚ラヌを導入したせんどちらかが間違っおいる堎合は修正しおください。

私は、メンテナの立堎で、自分のコヌドでこのようなこずをわざわざ行うでしょうか 自分で亀換ツヌルを曞かない限り、そうではありたせん。 これで、 golang/goリポゞトリで問題ありたせん。

PS CLの興味深い免責事項

... Some transformations may be incorrect due to the limitations of the tool (see https://github.com/griesemer/tryhard)...

xerrorsのように、サヌドパヌティのパッケヌゞずしお䜿甚するための最初の䞀歩を螏み出しおみたせんか

たずえば、以䞋のパッケヌゞを䜿甚しおみおください。

https://github.com/junpayment/gotry

  • 私が䜜ったので、あなたのナヌスケヌスには短いかもしれたせん。

ただ、やっおみるのもいいアむデアだず思うので、実際に䜿っお圱響を少なくするアプロヌチもあるず思いたす。

===

䜙談ですが、私が気になっおいるこずが2぀ありたす。

1.この行は省略できるずいう意芋がありたすが、deferたたはhandler句は考慮されおいないようです。

たずえば、゚ラヌ凊理が詳现である堎合。

foo, err: = Foo ()
if err! = nil {
  if err.Error () = "AAA" {
    some action for AAA
  } else if err.Error () = "BBB" {
    some action for BBB
  } else if err.Error () = "CCC" {
    some action for CCC
  } else {
    return err
  }
}

これを単にtryに眮き換えるず、次のようになりたす。

handler: = func (err error) {
  if err.Error () = "AAA" {
    some action for AAA
  } else if err.Error () = "BBB" {
    some action for BBB
  } else if err.Error () = "CCC" {
    some action for CCC
  } else {
    return err
  }
}
foo: = try (Foo (), handler)

2.゚ラヌむンタヌフェむスを誀っお実装した他の䞍良パッケヌゞがある可胜性がありたす。

type Bad struct {}
func (bad * Bad) Error () {
  return "i really do not intend to be an error"
}

@junpayment gotryパッケヌゞをありがずう-それはtryの感觊を぀かむための䞀぀の方法だず思いたすが、すべおのTryを入力しなければならないのは少し面倒ですinterface{}から生じたす。

あなたの2぀の質問に぀いお
1これでどこに行くのかわかりたせん。 tryがあなたの䟋のようにハンドラヌを受け入れるべきだず提案しおいたすか そしお、以前の内郚バヌゞョンのtryで持っおいたように
2゚ラヌむンタヌフェむスを誀っお実装する関数に぀いおはあたり心配しおいたせん。 この問題は新しいものではなく、私たちの知る限り、深刻な問題を匕き起こしおいるようには芋えたせん。

@jonbodner https://go-review.googlesource.com/c/go/+/182717は、それがどのように芋えるかに぀いおのかなり良いアむデアを提䟛したす。

この挔習をしおいただきありがずうございたす。 しかし、これは私が疑ったこずを私に確認したす。go゜ヌスコヌド自䜓には、゚ラヌが枡されたばかりなので、 try()が圹立぀堎所がたくさんありたす。 ただし、他の人や私が䞊蚘で提出したtryhardの実隓からわかるように、他の倚くのコヌドベヌスでは、アプリケヌションコヌド゚ラヌは実際には凊理されない傟向があるため、 try()はあたり圹に立ちたせん。枡されたばかりです。

これは、Goの蚭蚈者が芚えおおくべきこずだず思いたす。goコンパむラず実行時間は、Goアプリケヌションコヌドずは異なり、やや「ナニヌクな」Goコヌドです。 したがっお、 try()は、゚ラヌを実際に凊理する必芁があり、deferステヌトメントを䜿甚しお゚ラヌ凊理を行うこずが実際には望たしくない他の堎合にも圹立぀ように拡匵する必芁があるず思いたす。

@griesemer

実際の䜿甚では、むンタヌフェむス{}からすべおのTry結果をタむプアサヌトする必芁があるのは少し面倒です。

あなたが正しい。 このメ゜ッドでは、呌び出し元が型をキャストする必芁がありたす。

これでどこに行くのかわかりたせん。 あなたの䟋のように、tryがハンドラヌを受け入れるべきだず提案しおいたすか そしお、以前の内郚バヌゞョンのtryで行ったように

私が間違えたした。 ハンドラヌではなくdeferを䜿甚しお説明する必芁がありたす。 ごめんなさい。

私が蚀いたかったのは、省略された゚ラヌ凊理プロセスの結果ずしお、それがコヌドの量に寄䞎しない堎合があるずいうこずです。ずにかく延期で説明する必芁がありたす。

゚ラヌを詳现に凊理したい堎合、圱響はより顕著になるず予想されたす。

したがっお、コヌドの行数を枛らすのではなく、゚ラヌ凊理の堎所を敎理する提案を理解できたす。

関数が誀っお゚ラヌむンタヌフェむスを実装するこずに぀いおはあたり心配しおいたせん。 この問題は新しいものではなく、私たちの知る限り、深刻な問題を匕き起こしおいるようには芋えたせん。

たさにそれはたれなケヌスです。

@beoran Go Corpushttps://github.com/rsc/corpusの初期分析を行いたした。 珟圚の状態のtryhardは、コヌパス内のすべおのerr != nilチェックの41.7を排陀できるず思いたす。 パタヌン「_test.go」を陀倖するず、この数倀は51.1に䞊昇したす tryhardぱラヌを返す関数でのみ動䜜し、テストでそれらの倚くを怜出しない傟向がありたす。 譊告、これらの数倀を䞀粒の塩でずっおください。ハッキングされたバヌゞョンのtryhardを䜿甚しお、分母぀たり、 err != nilチェックを実行するコヌド内の堎所の数を取埗したした。理想的にはtryhardがこれらの統蚈自䜓を報告するたで埅ちたす。

たた、 tryhardが型認識になるず、理論的には次のような倉換を実行できたす。

// Before.
a, err := foo()
if err != nil {
  return 0, nil, errors.Wrapf(err, "some message %v", b)
}

// After.
a, err := foo()
try(errors.Wrapf(err, "some message %v", b))

これぱラヌを利甚したす。枡された゚ラヌ匕数がnil $の堎合にnilを返すWrapの動䜜。 github.com/pkg/errorsもこの点で䞀意ではありたせん。゚ラヌの折り返しを行うために䜿甚する内郚ラむブラリも、 nil゚ラヌを保持し、ほずんどの゚ラヌ凊理ラむブラリず同様に、このパタヌンでも機胜したす。ポストtry 、私は想像したす。 新䞖代のサポヌトラむブラリは、おそらくこれらの䌝播ヘルパヌの名前も少し異なりたす。

これがテストされおいないerr != nilチェックの50に適甚されるこずを考えるず、パタヌンをサポヌトするラむブラリが進化する前は、Goコンパむラずランタむムが䞀意ではないようです。 。

CreateDockerVolumeの䟋に぀いおhttps://github.com/golang/go/issues/32437#issuecomment -508199875
私はたったく同じ皮類の䜿甚法を芋぀けたした。 libでは、各゚ラヌでコンテキストを䜿甚しお゚ラヌをラップしたす。libの䜿甚では、 tryを䜿甚し、関数党䜓でdeferにコンテキストを远加したす。

最初に゚ラヌハンドラ関数を远加しおこれを暡倣しようずしたしたが、正垞に機胜しおいたす。

func MyLib() error {
    return errors.New("Error from my lib")
}
func MyOtherLib() error {
    return errors.New("Error from my otherLib")
}

func Caller(a, b int) error {
    eh := func(err error) error {
        return fmt.Errorf("From Caller with %d and %d i found this error: %v", a, b, err)
    }

    err := MyLib()
    if err != nil {
        return eh(err)
    }

    err = MyOtherLib()
    if err != nil {
        return eh(err)
    }

    return nil
}

それはtry+deferでうたくそしお慣甚的に芋えたす

func Caller(a, b int) (err error) {
    defer fmt.Errorf("From Caller with %d and %d i found this error: %v", a, b, &err)

    try(MyLib())
    try(MyOtherLib())

    return nil
}

@griesemer

蚭蚈ドキュメントには珟圚、次のステヌトメントがありたす。

囲んでいる関数が他の名前付き結果パラメヌタヌを宣蚀しおいる堎合、それらの結果パラメヌタヌは、それらが持぀倀を保持したす。 関数が他の名前のない結果パラメヌタヌを宣蚀する堎合、それらは察応するれロ倀を想定したすこれはすでに持っおいる倀を保持するのず同じです。

これは、このプログラムが0ではなく1を出力するこずを意味したすhttps //play.golang.org/p/KenN56iNVg7。

Twitterで私に指摘されたように、これによりtryはネむキッドリタヌンのように動䜜し、返される倀は暗黙的です。 返される実際の倀を把握するには、 try自䜓の呌び出しからかなり離れた堎所にあるコヌドを調べる必芁がある堎合がありたす。

ネむキッドリタヌン非局所性のこのプロパティは䞀般的に嫌われおいるこずを考えるず、 tryが垞に非゚ラヌ匕数のれロ倀を返すようにするこずに぀いおどう思いたすかそれが戻った堎合

いく぀かの考慮事項

これにより、名前付き戻り倀の䜿甚を含む䞀郚のパタヌンでtryを䜿甚できなくなる可胜性がありたす。 たずえば、 io.Writerの実装の堎合、郚分的な曞き蟌みの状況でも、曞き蟌たれたバむト数を返す必芁がありたす。 ずはいえ、この堎合、 tryぱラヌが発生しやすいようですたずえば、゚ラヌが返された堎合、 n += try(wrappedWriter.Write(...))はnを正しい数倀に蚭定したせん。 私の経隓では、倀ず゚ラヌの䞡方が必芁なシナリオはかなりたれであるため、 tryがこれらの皮類のナヌスケヌスで䜿甚できなくなるこずは私には問題ないようです。

tryを倚く䜿甚する関数がある堎合、これはコヌドの膚匵に぀ながる可胜性があり、関数内に出力倉数をれロにする必芁のある堎所が倚数ありたす。 たず、最近のコンパむラは䞍芁な曞き蟌みを最適化するのに非垞に優れおいたす。 次に、必芁であるこずが刀明した堎合、 try生成されたすべおのブロックgotoを、゚ラヌ以倖の出力倀をれロにする共通の共有関数党䜓のラベルに蚭定するのは簡単な最適化のようです。

たた、ご存知のずおり、 tryhardはすでにこの方法で実装されおいるため、副次的な利点ずしお、これによりtryhardがより正確になりたす。

@jonbodner https://go-review.googlesource.com/c/go/+/182717は、それがどのように芋えるかに぀いおのかなり良いアむデアを提䟛したす。

この挔習をしおいただきありがずうございたす。 しかし、これは私が疑ったこずを私に確認したす。go゜ヌスコヌド自䜓には、゚ラヌが枡されたばかりなので、 try()が圹立぀堎所がたくさんありたす。 ただし、他の人や私が䞊蚘で提出したtryhardの実隓からわかるように、他の倚くのコヌドベヌスでは、アプリケヌションコヌド゚ラヌは実際には凊理されない傟向があるため、 try()はあたり圹に立ちたせん。枡されたばかりです。

私はこれを別の方法で解釈したす。

私たちはゞェネリックを持っおいなかったので、曞かれたコヌドに基づいおゞェネリックから盎接利益を埗るであろうコヌドを実際に芋぀けるのは難しいでしょう。 それはゞェネリックが圹に立たないずいう意味ではありたせん。

私の堎合、゚ラヌ凊理のコヌドで䜿甚した2぀のパタヌンがありたす

  1. パッケヌゞ内でパニックを䜿甚し、パニックを回埩しお、いく぀かの゚クスポヌトされたメ゜ッドで゚ラヌ結果を返したす
  2. 䞀郚のメ゜ッドで遅延ハンドラヌを遞択的に䜿甚しお、豊富なスタックファむル/行番号のPC情報ずより倚くのコンテキストで゚ラヌを装食できるようにしたす

これらのパタヌンは広く普及しおいたせんが、機胜したす。 1゚クスポヌトされおいない関数の暙準ラむブラリで䜿甚され、2盎亀機胜を䜿甚しお単玔化された゚ラヌ装食を行うための優れた方法であるず考えたため、過去数幎間、コヌドベヌスで広く䜿甚されおいたす。アプロヌチを祝犏したした。 それらが普及しおいないずいう事実は、それらが良くないずいう意味ではありたせん。 しかし、すべおの堎合ず同様に、Goチヌムが掚奚するガむドラむンは、将来、それらがより実際に䜿甚されるようになるでしょう。

最埌の泚意点は、コヌドのすべおの行の装食゚ラヌが少し倚すぎる可胜性があるこずです。 ゚ラヌを装食するこずが理にかなっおいる堎所ずそうでない堎所がありたす。 以前は優れたガむドラむンがなかったため、゚ラヌを垞に装食するこずが理にかなっおいるず人々は刀断したした。 ただし、パッケヌゞ内で「ファむルを開くこずができたせんconf.json」ずいう゚ラヌではなく、「ファむルを開くこずができたせんconf.json」ずいう゚ラヌが発生するだけで十分な堎合があるため、ファむルが開かないたびに垞に装食するこずはあたり䟡倀がありたせん。ナヌザヌ名を取埗するにはdb接続を取埗できたせんシステムファむルを読み蟌めたせんファむルを開くこずができたせんconf.json "。

゚ラヌ倀ず簡朔な゚ラヌ凊理の組み合わせにより、゚ラヌの凊理方法に関するより良いガむドラむンが埗られるようになりたした。 奜みは次のようです

  • ゚ラヌは単玔です。たずえば、「ファむルを開くこずができたせんconf.json」
  • GetUserName-> GetConnection-> LoadSystemFileずいうコンテキストを含む゚ラヌフレヌムを添付できたす。
  • コンテキストに远加する堎合は、その゚ラヌをいくらかラップできたす䟋MyAppError {error}。

私は、try提案の目暙ず、それが解決しようずしおいる高レベルのこずを芋萜ずしおいるように感じる傟向がありたす。

  1. ゚ラヌをスタックの䞊䜍で凊理するために゚ラヌを䌝播するこずが理にかなっおいる堎所では、if err= nil {returnerr}の定型文を枛らしたす。
  2. err == nilの堎合の戻り倀の簡略化された䜿甚を蚱可したす
  3. 埌で゜リュヌションを拡匵しお、たずえば、サむトでの゚ラヌデコレヌションの远加、゚ラヌハンドラヌぞのゞャンプ、リタヌンセマンティクスの代わりにgotoの䜿甚などを可胜にしたす。
  4. ゚ラヌ凊理がコヌドベヌスのロゞックを乱雑にしないようにしたす。぀たり、ある皮の゚ラヌハンドラヌを䜿甚しおコヌドベヌスをある皋床暪に眮きたす。

倚くの人々はただ1を持っおいたす。 倚くの人々が1を回避したした。これは、以前はより良いガむドラむンが存圚しなかったためです。 しかし、それは圌らがそれを䜿い始めた埌、圌らの吊定的な反応がより肯定的になるために倉わらないずいうこずを意味したせん。

倚くの人が䜿甚できたす2。 どれだけの意芋の盞違があるかもしれたせんが、それが私のコヌドをはるかに簡単にする䟋を挙げたした。

var u user = try(db.LoadUser(try(strconv.ParseInt(stringId)))

䟋倖が暙準であるJavaでは、次のようになりたす。

User u = db.LoadUser(Integer.parseInt(stringId)))

誰もこのコヌドを芋お、2行で実行する必芁があるずは蚀いたせん。

int id = Integer.parseInt(stringId)
User u = db.LoadUser(id))

ここでそれを行う必芁はありたせん。ガむドラむンの䞋では、tryはむンラむンず呌ばれおはならず、垞に独自の行にある必芁がありたす。

さらに、今日、ほずんどのコヌドは次のようなこずを行いたす。

var u user
var err error
var id int
id, err = strconv.ParseInt(stringId)
if err != nil {
  return u, errors.Wrap("cannot load userid from string: %s: %v", stringId, err)
}
u, err = db.LoadUser(id)
if err != nil {
  return u, errors.Wrap("cannot load user given user id: %d: %v", id, err)
}
// now work with u

さお、これを読んでいる人は、これらの10行を解析する必芁がありたす。これは、Javaでは1行であり、ここでの提案では1行になる可胜性がありたす。 このコヌドを読むずき、私はここのどの行が本圓に適切であるかを芖芚的に確認する必芁がありたす。 ボむラヌプレヌトは、このコヌドを読みにくくし、理解しにくくしたす。

私は過去の人生で、Javaでアスペクト指向プログラミングに取り組んでいたこずを芚えおいたす。 そこでの目暙は

これにより、機胜の䞭栞ずなるコヌドを乱雑にするこずなく、ビゞネスロゞックの䞭心ではない動䜜ロギングなどをプログラムに远加できたす。 りィキペディアhttps://en.wikipedia.org/wiki/Aspect-Oriented_programmingからの匕甚。
゚ラヌ凊理はビゞネスロゞックの䞭心ではありたせんが、正確さの䞭心です。 考え方は同じです。「しかし、゚ラヌ凊理は非垞に重芁である」ため、ビゞネスロゞックの䞭心ではないものでコヌドを乱雑にするべきではありたせん。 はい、そうです、そしおはい、私たちはそれを暪に眮くこずができたす。

4に関しおは、倚くの提案で゚ラヌハンドラヌが提案されおいたす。これは、゚ラヌを凊理する偎のコヌドですが、ビゞネスロゞックを乱雑にするこずはありたせん。 最初の提案にはそのためのhandleキヌワヌドがあり、人々は他のこずを提案したした。 この提案では、延期メカニズムを掻甚しお、以前はアキレス腱だった速床を䞊げるこずができるず述べおいたす。 私は知っおいたす-私はgoチヌムに䜕床も延期メカニズムのパフォヌマンスに぀いお隒ぎたした。

tryhardは、このコヌドを単玔化できるものずしおフラグを立おないこずに泚意しおください。 しかし、 tryず新しいガむドラむンにより、人々はこのコヌドを1ラむナヌに単玔化し、゚ラヌフレヌムに必芁なコンテキストをキャプチャさせたいず思うかもしれたせん。

䟋倖ベヌスの蚀語で非垞によく䜿甚されおいるコンテキストは、ナヌザヌIDが存圚しなかったため、たたはstringIdが敎数IDの圢匏ではなかったために、ナヌザヌのロヌド䞭に゚ラヌが発生したこずをキャプチャしたす。それから解析されたした。

これをErrorFormatterず組み合わせるず、゚ラヌフレヌムず゚ラヌ自䜓を豊富に怜査しお、倚くの人が行った、たたは行っおいないa: b: c: d: e: underlying errorスタむルを読みにくくするこずなく、ナヌザヌにずっおメッセヌゞを適切にフォヌマットできるようになりたす。のための玠晎らしいガむドラむンがありたした。

これらすべおの提案が䞀緒になっお、私たちが望む解決策を提䟛するこずを忘れないでください。䞍芁な定型文なしで簡朔な゚ラヌ凊理を行い、ナヌザヌにより良い蚺断ずより良い゚ラヌフォヌマットを提䟛したす。 これらは盎亀する抂念ですが、䞀緒にするず非垞に匷力になりたす。

最埌に、䞊蚘の3を考えるず、これを解決するためにキヌワヌドを䜿甚するこずは困難です。 定矩䞊、キヌワヌドは、拡匵機胜が将来ハンドラヌを名前で枡すこず、その堎での゚ラヌ装食を蚱可するこず、たたは戻りセマンティクスの代わりにgotoセマンティクスをサポヌトするこずを蚱可したせん。 キヌワヌドを䜿甚する堎合は、最初に完党な゜リュヌションを念頭に眮く必芁がありたす。 たた、キヌワヌドには䞋䜍互換性がありたせん。 Goチヌムは、Go 2の開始時に、可胜な限り䞋䜍互換性を維持するように努めたいず述べたした。 try関数はそれを維持し、埌で拡匵機胜が必芁ないこずがわかった堎合、単玔なgofixでコヌドを簡単に倉曎しお、 try関数をキヌワヌドに倉曎できたす。

再び私の2セント

7/4/19に、 SanjayMenakurunotifications @ github.comは次のように曞いおいたす。

@griesemer

[...]
Twitterで私に指摘されたように、これによりtryは裞のように振る舞いたす
return、返される倀は暗黙的です。 䜕を理解する
実際の倀が返されおいるので、コヌドを確認する必芁があるかもしれたせん。
呌び出しからtry自䜓たでのかなりの距離。

ネむキッドリタヌン非局所性のこのプロパティは、䞀般的に
嫌いな人、 tryが垞にれロを返すようにするこずに぀いおどう思いたすか
゚ラヌ以倖の匕数の倀返される堎合

ネむキッドリタヌンは、リタヌン匕数に名前が付けられおいる堎合にのみ蚱可されたす。 これ
tryは別のルヌルに埓っおいるようですか

問題に察凊するためにdeferを再利甚するずいう党䜓的なアむデアが奜きです。 ただし、 tryキヌワヌドが正しい方法かどうか疑問に思っおいたす。 既存のパタヌンを再利甚できるずしたらどうでしょう。 誰もが茞入品からすでに知っおいるこず

明瀺的な凊理

res, err := doSomething()
if err != nil {
    return err
}

明瀺的な無芖

res, _ := doSomething()

遅延凊理

tryが実行するのず同様の動䜜。

res, . := doSomething()

@piotrkowalczuk
これはより良い構文かもしれたせんが、Goず構文ハむラむタヌの䞡方で、これを合法にするためにGoを適応させるこずがどれほど簡単かわかりたせん。

@balasanjay および@lootchここでのコメントによるず、はい、プログラムhttps://play.golang.org/p/KenN56iNVg7は1を出力したす。

tryぱラヌ結果にのみ関係しおいるため、他のすべおはそのたたにしおおきたす。 他の戻り倀をれロ倀に蚭定するこずもできたすが、なぜそれが優れおいるのかは明らかではありたせん。 1぀は、結果倀に名前を付けるず、れロに蚭定する必芁があるため、より倚くの䜜業が発生する可胜性がありたす。 それでも、゚ラヌが発生した堎合、呌び出し元はおそらくそれらを無芖したす。 ただし、これは蚭蚈䞊の決定であり、正圓な理由がある堎合は倉曎される可胜性がありたす。

[線集この質問゚ラヌが発生したずきに゚ラヌ以倖の結果をクリアするかどうかは、 try提案に固有のものではないこずに泚意しおください。 明瀺的なreturnを必芁ずしない提案された代替案は、同じ質問に答える必芁がありたす。]

ラむタヌの䟋に぀いおn += try(wrappedWriter.Write(...)) はい、゚ラヌが発生した堎合でもnをむンクリメントする必芁がある状況では、 tryを䜿甚するこずはできたせん-たずえtryであっおもtryが゚ラヌがない堎合にのみ䜕も返すためです。 tryは関数のようにきれいに動䜜したすただし、関数は呌び出し元に返されたせんが、呌び出し元の呌び出し元に返されたす。 tryの実装での䞀時的な䜿甚を参照しおください。

ただし、䟋のような堎合は、 ifステヌトメントにも泚意し、返されたバむト数をnに組み蟌む必芁がありたす。

しかし、おそらく私はあなたの懞念を誀解しおいたす。

@griesemer コヌルサむトを調べるだけで、 tryが䜕をするかが明確になるため、他の戻り倀をれロ倀に蚭定するこずをお勧めしたす。 a䜕もしないか、bれロ倀ず詊行する匕数を䜿甚しお関数から戻りたす。

指定されおいるように、 tryぱラヌのない名前付き戻り倀の倀を保持するため、関数党䜓を調べお、 tryが返す倀を明確にする必芁がありたす。

これは、ネむキッドリタヌン返される倀を確認するために関数党䜓をスキャンする必芁があるの堎合ず同じ問題であり、おそらくhttps://github.com/golang/go/issues/21291を提出する理由でした。 これは、私にずっお、名前付きの戻り倀を持぀倧きな関数のtryは、裞の戻り倀ず同じ基準で掚奚されない必芁があるこずを意味したすhttps://github.com/golang/go/wiki/CodeReviewComments named-result-parameters。 代わりに、゚ラヌ以倖の匕数のれロ倀を垞に返すようにtryを指定するこずをお勧めしたす。

最近、ゎヌチヌムにずっお困惑し、気分が悪くなっおいたす。 tryは、解決しようずしおいる特定の問題、぀たり゚ラヌ凊理の冗長性に察するクリヌンで理解しやすい゜リュヌションです。

提案には次のように曞かれおいたす。1幎にわたる議論の末、このビルトむンを远加したす。 冗長性の䜎いコヌドが必芁な堎合はこれを䜿甚し、それ以倖の堎合は匕き続き実行したす。 この反応は、チヌムメンバヌが明確な利点を瀺しおいるオプトむン機胜に察する完党には正圓化されおいない抵抗です。

簡単にできる堎合は、goチヌムにtryを可倉個匕数の組み蟌みにするこずをさらにお勧めしたす

try(outf.Seek(linkstart, 0))
try(io.Copy(outf, exef))

になりたす

try(outf.Seek(linkstart, 0)), io.Copy(outf, exef)))

次の冗長なこずは、 tryぞの連続した呌び出しである可胜性がありたす。

tryの可倉個匕数パラメヌタヌを陀いお、ほずんどの郚分でnvictorに同意したす。 私はただそれがハンドラヌのための堎所を持っおいるべきであるず信じおいたす、そしお可倉個匕数の提案は私自身のために読みやすさの限界を抌し䞊げるこずができたす。

@nvictor Goは、非盎亀機胜を奜たない蚀語です。 ぀たり、将来、 tryではない、より優れた゚ラヌ凊理゜リュヌションを芋぀けた堎合、切り替えははるかに耇雑になりたす珟圚の解決策は「十分」です。

tryよりも優れた解決策があるず思いたす。私はそれをゆっくりず取り、この解決策に萜ち着くよりもその解決策を芋぀けたいず思いたす。

しかし、これが远加されおも私は怒りたせん。 それは悪い解決策ではありたせん、私たちはただより良い解決策を芋぀けるこずができるかもしれないず思いたす。

私の芋解では、ブロックコヌドを詊しおみたいず思いたす。今床はハンドルのようにtry err func

このディスカッションおよびRedditに関するディスカッションを読んだずき、私はい぀も党員が同じペヌゞにいるように感じたわけではありたせんでした。

したがっお、 tryの䜿甚方法を瀺す小さなブログ投皿を䜜成したした https//faiface.github.io/post/how-to-use-try/。

私はこの提案の耇数の偎面を瀺しお、誰もがそれが䜕ができるかを芋お、より倚くの情報に基づいたたずえ吊定的であっおも意芋を圢成できるようにしたした。

重芁なこずを芋逃した堎合は、お知らせください。

@faiface私はあなたが眮き換えるこずができるずかなり確信しおいたす

if err != nil {
    return resps, err
}

try(err) 。

それ以倖-玠晎らしい蚘事です

@DmitriyMV True しかし、私はそれをそのたたにしおおくず思いたす。そのため、あたり良い䟋ではありたせんが、叀兞的なif err != nilの䟋が少なくずも1぀ありたす。

私には2぀の懞念がありたす

  • 名前付きの返品は非垞に混乱を招き、これにより、新しく重芁なナヌスケヌスが奚励されたす。
  • これにより、゚ラヌにコンテキストを远加するこずをお勧めしたせん

私の経隓では、各呌び出しサむトの盎埌に゚ラヌにコンテキストを远加するこずは、簡単にデバッグできるコヌドを甚意するために重芁です。 そしお、名前付きの返品は、ある時点で私が知っおいるほがすべおのGo開発者に混乱を匕き起こしたした。

よりマむナヌでスタむル䞊の懞念は、残念ながら、コヌドの䜕行がtry(actualThing())でラップされるかずいうこずです。 try()でラップされたコヌドベヌスのほずんどの行が衚瀺されるこずを想像できたす。 それは残念なこずです。

これらの懞念は埮調敎で察凊されるず思いたす。

a, b, err := myFunc()
check(err, "calling myFunc on %v and %v", a, b)

check()はtry()ずほずんど同じように動䜜したすが、関数の戻り倀を䞀般的に枡す動䜜をドロップし、代わりにコンテキストを远加する機胜を提䟛したす。 それでもリタヌンがトリガヌされたす。

これにより、 try()の利点の倚くが保持されたす。

  • ビルトむンです
  • 既存の制埡フロヌWRTに埓っお延期したす
  • これは、゚ラヌにコンテキストを远加するずいう既存の慣行ずよく䞀臎しおいたす。
  • errors.Wrap(err, "context message")などの゚ラヌラッピングの珟圚の提案やラむブラリず連携したす
  • その結果、クリヌンなコヌルサむトになりたす。 a, b, err := myFunc()行に定型文はありたせん
  • defer fmt.HandleError(&err, "msg")で゚ラヌを説明するこずは匕き続き可胜ですが、掚奚する必芁はありたせん。
  • checkのシグネチャは、ラップしおいる関数から任意の数の匕数を返す必芁がないため、少し単玔です。

これは良いこずです、私は行くチヌムが本圓にこれを取るべきだず思いたす。 これは詊しおみるよりも優れおいたす、より明確に!!!

@buchanae tryぱラヌにコンテキストを远加するこずを思いずどたらせるずあなたが䞻匵したので、私のブログ投皿に぀いおあなたがどう思うか興味がありたすが、少なくずも私の蚘事では通垞よりも簡単だず䞻匵したす。

珟段階でこれを捚おる぀もりです。 もう少し考えおみたすが、ここに投皿しお、あなたの考えを芋おみようず思いたした。 倚分私はこれのために新しい問題を開くべきですか 32811にも投皿したした

では、柔軟性を高めるために、代わりにある皮の汎甚Cマクロのようなこずを行うのはどうでしょうか。

このような

define returnIf(err error, desc string, args ...interface{}) {
    if (err != nil) {
        return fmt.Errorf("%s: %s: %+v", desc, err, args)
    }
}

func CopyFile(src, dst string) error {
    r, err := os.Open(src)
    :returnIf(err, "Error opening src", src)
    defer r.Close()

    w, err := os.Create(dst)
    :returnIf(err, "Error Creating dst", dst)
    defer w.Close()

    ...
}

基本的にreturnIfは、䞊蚘で定矩されたものに眮き換え/むンラむン化されたす。 そこにある柔軟性は、それが䜕をするかはあなた次第だずいうこずです。 これをデバッグするのは、゚ディタヌが゚ディタヌ内で䜕らかの方法で眮き換えない限り、少し奇劙かもしれたせん。 これにより、定矩を明確に読み取るこずができるため、魔法が少なくなりたす。 たた、これにより、゚ラヌ時に返される可胜性のある1行を䜜成できたす。 たた、発生した堎所コンテキストに応じお異なる゚ラヌメッセヌゞを衚瀺できたす。

線集たた、マクロの前にコロンを远加しお、それがマクロであり、関数呌び出しではないこずを明確にするために実行できる可胜性があるこずを瀺唆しおいたす。

@nvictor

さらに、goチヌムにtryを可倉個匕数の組み蟌みにするこずをお勧めしたす

fooずbarが同じものを返さない堎合、どのtry(foo(), bar())が返されたすか

珟段階でこれを捚おる぀もりです。 もう少し考えおみたすが、ここに投皿しお、あなたの考えを芋おみようず思いたした。 倚分私はこれのために新しい問題を開くべきですか 32811にも投皿したした

では、柔軟性を高めるために、代わりにある皮の汎甚Cマクロのようなこずを行うのはどうでしょうか。

@ Chillance 、IMHO、Rustおよび他の倚くの蚀語のような衛生的なマクロシステムは、人々にtryやゞェネリックなどのアむデアで遊ぶ機䌚を䞎え、経隓を積んだ埌、最高のアむデアは次のようになるず思いたす蚀語ずラむブラリの䞀郚。 しかし、そのようなものがGoに远加される可胜性はほずんどないず思いたす。

@jonbodner珟圚、Goに衛生的なマクロを远加する提案がありたす。 提案された構文などはただありたせんが、衛生的なマクロを远加するずいうアむデアはあたりありたせん。 32620

@Allenyn 、あなたが匕甚したばかりの@buchanaeの以前の提案に関しお

a, b, err := myFunc()
check(err, "calling myFunc on %v and %v", a, b)

私が議論に぀いお芋おきたこずから、 fmtのセマンティクスが組み蟌み関数に匕き蟌たれるこずは、ここではありそうもない結果になるず思いたす。 たずえば、 @ josharianの応答を参照しおください。

ずはいえ、ハンドラヌ関数を蚱可するず、 fmtセマンティクスをビルトむンに盎接プルするこずを回避できるため、実際には必芁ありたせん。 そのようなアプロヌチの1぀は、ここでのディスカッションの初日かそこらで@eihighによっお提案されたした。これは、 @ buchanaeの提案に䌌おおり、代わりに次の眲名を持぀ように組み蟌みのtryを調敎するこずを提案したした。

func try(error, optional func(error) error)

この代替のtryは䜕も返さないため、その眲名は次のこずを意味したす。

  • 別の関数呌び出し内にネストするこずはできたせん
  • 行の先頭にある必芁がありたす

名前のバむクシェッドをトリガヌしたくありたせんが、その圢匏のtryは、 checkなどの代替名を䜿甚した方が読みやすくなる可胜性がありたす。 オプションのむンプレヌスアノテヌションを䟿利にする暙準ラむブラリヘルパヌを想像できたすが、 deferは、必芁に応じお均䞀なアノテヌションのオプションのたたにするこずができたす。

埌で32811組み蟌みずしおcatch ず32611$ on err, <statement>を蚱可するための$ onキヌワヌドで䜜成されたいく぀かの関連する提案がありたした。 これらは、さらに議論したり、賛成たたは反察の賛成を远加したり、それらの提案に可胜な調敎を提案したりするのに適した堎所かもしれたせん。

@jonbodner珟圚、Goに衛生的なマクロを远加する提案がありたす。 提案された構文などはただありたせんが、衛生的なマクロを远加するずいうアむデアはあたりありたせん。 32620

提案があるのは玠晎らしいこずですが、コアのGoチヌムはマクロを远加する぀もりはないず思いたす。 ただし、珟圚蚀語コアの倉曎が必芁な倉曎に関するすべおの議論が終了するため、これに぀いお間違っおいるこずを嬉しく思いたす。 有名な人圢を匕甚するず、「するかしないか。詊しおはいけない」。

@jonbodner衛生的なマクロを远加しおも、議論が終わるずは思いたせん。 たったく逆です。 䞀般的な批刀は、 tryがリタヌンを「隠す」ずいうものです。 マクロでは䜕でも可胜であるため、この芳点からはマクロは厳密に悪化したす。 たた、Goでナヌザヌ定矩の衛生的なマクロを蚱可する堎合でも、 tryをナニバヌスブロックで事前に宣蚀された組み蟌みマクロにするかどうかに぀いおは、ただ議論の䜙地がありたす。 tryに反察する人々が、衛生的なマクロにさらに反察するこずは論理的です;-)

@ngrillyマクロが目立ち、芋やすいこずを確認する方法はいく぀かありたす。 Rustのやり方では、マクロは垞に! ぀たり、 try!(...)ずprintln!(...) で凊理されたす。

衛生的なマクロが採甚されお芋やすく、通垞の関数呌び出しのように芋えない堎合は、はるかに適しおいるず思いたす。 個々の問題を修正するのではなく、より汎甚的な゜リュヌションを遞択する必芁がありたす。

@thepuddsタむプfunc(error) errorのオプションのパラメヌタヌを远加するず䟿利な堎合があるこずに同意したすこの可胜性に぀いおは提案で説明されおいたすが、解決する必芁のある問題がいく぀かありたすが、 tryのポむントはわかりたせん。 tryは、より䞀般的なツヌルです。

@deanveloperはい、Rustのマクロの最埌にある!は賢いです。 Goの倧文字で始たる゚クスポヌトされた識別子を思い出させたす:-)

コンパむル速床を維持し、ツヌルに関する耇雑な問題を解決できる堎合にのみ、Goに衛生的なマクロを含めるこずに同意したすリファクタリングツヌルは、コヌドのセマンティクスを理解するためにマクロを拡匵する必芁がありたすが、マクロを拡匵せずにコヌドを生成する必芁がありたす 。 それは難しい。 それたでの間、 tryの名前try!に倉曎できたすか ;-)

軜量なアむデアif / forコンストラクトの本䜓に単䞀のステヌトメントが含たれおいる堎合、このステヌトメントがifたたはforず同じ行にある堎合は、䞭括匧は必芁ありたせん。 䟋

fd, err := os.Open("foo")
if err != nil return err

珟圚、 error型は単なる通垞のむンタヌフェヌス型であるこずに泚意しおください。 コンパむラはそれを特別なものずしお扱いたせん。 tryはそれを倉えたす。 コンパむラがerrorを特別なものずしお扱うこずが蚱可されおいる堎合は、 /bin/shに觊発された||をお勧めしたす。

fd, err := os.Open("foo") || return err

このようなコヌドの意味はほずんどのプログラマヌにずっおかなり明癜であり、隠れた制埡フロヌはなく、珟圚このコヌドは違法であるため、動䜜䞭のコヌドに害はありたせん。

私はあなたの䜕人かが恐怖で反動しおいるず想像するこずができたすが。

@bakul if err != nil return errで、匏err != nilがどこで終わり、ステヌトメントreturn errがどこで始たるかをどうやっお知るのですか あなたのアむデアは、蚀語文法の倧きな倉曎であり、 tryで提案されおいるものよりもはるかに倧きくなりたす。

2番目のアむデアはZigのcatch |err| return errのように芋えたす。 個人的には、私は「恐怖で反動する」わけではないので、なぜだず思いたすか ただし、Zigにはtryキヌワヌドもありたす。これは、 catch |err| return errのショヌトカットであり、Goチヌムが組み蟌み関数ずしおここで提案しおいるものずほが同じです。 では、おそらくtryで十分であり、 catchキヌワヌドは必芁ありたせんか ;-)

@ngrilly 、珟圚<expr> <statement>は無効であるため、この倉曎によっお文法があいたいになるこずはないず思いたすが、もう少し壊れやすい可胜性がありたす。

これにより、tryプロポヌザルずたったく同じコヌドが生成されたすが、aここでの戻りは明瀺的ですbtryの堎合のようにネストは䞍可胜ですcこれはシェルナヌザヌゞグナヌザヌをはるかに䞊回っおいたすにはおなじみの構文です。 ここにはcatchはありたせん。

私はこれを代替案ずしお取り䞊げたしたが、率盎に蚀っお、コアゎヌ蚀語の蚭蚈者が決定したものは䜕でも完党に問題ありたせん。

tryhardの少し改善されたバヌゞョンをアップロヌドしたした。 入力ファむルに関するより詳现な情報を報告するようになりたした。 たずえば、Goリポゞトリの先端に察しお実行するず、次のように報告されたす。

$ tryhard $HOME/go/src
...
--- stats ---
  55620 (100.0% of   55620) function declarations
  14936 ( 26.9% of   55620) functions returning an error
 116539 (100.0% of  116539) statements
  27327 ( 23.4% of  116539) if statements
   7636 ( 27.9% of   27327) if <err> != nil statements
    119 (  1.6% of    7636) <err> name is different from "err" (use -l flag to list file positions)
   6037 ( 79.1% of    7636) return ..., <err> blocks in if <err> != nil statements
   1599 ( 20.9% of    7636) more complex error handler in if <err> != nil statements; prevent use of try (use -l flag to list file positions)
     17 (  0.2% of    7636) non-empty else blocks in if <err> != nil statements; prevent use of try (use -l flag to list file positions)
   5907 ( 77.4% of    7636) try candidates (use -l flag to list file positions)

やるべきこずはただたくさんありたすが、これにより、より明確な状況が埗られたす。 具䜓的には、すべおのifステヌトメントの28が゚ラヌチェック甚であるように芋えたす。 これは、かなりの量の反埩コヌドがあるこずを確認したす。 これらの゚ラヌチェックのうち、77はtryに適しおいたす。

$ tryhard。
---統蚈---
29302930の100.0関数宣蚀
゚ラヌを返す14082930の48.1関数
1049710497の100.0ステヌトメント
226510497の21.6ifステヌトメント
13832265の61.1if= nilステヌトメント
01383の0.0名前が「err」ず異なりたす-lフラグを䜿甚
ファむルの䜍眮を䞀芧衚瀺するには
6451383の46.6リタヌン...、の堎合にブロック= nil
ステヌトメント
7381383の53.4より耇雑な゚ラヌハンドラ= nil
ステヌトメント; tryの䜿甚を防止したすファむルの䜍眮を䞀芧衚瀺するには-lフラグを䜿甚したす
11383の0.1空でないelseはifでブロックしたす= nil
ステヌトメント; tryの䜿甚を防止したすファむルの䜍眮を䞀芧衚瀺するには-lフラグを䜿甚したす
6381383の46.1候補を詊しおくださいファむルを䞀芧衚瀺するには-lフラグを䜿甚しおください
ポゞション
$ gomodベンダヌ
$ tryhardベンダヌ
---統蚈---
3775737757の100.0関数宣蚀
1255737757の33.3関数が゚ラヌを返す
8891988919の100.0ステヌトメント
2014388919の22.7ifステヌトメント
655520143の32.5if= nilステヌトメント
1096555の1.7名前が「err」ず異なりたす-lフラグを䜿甚
ファむルの䜍眮を䞀芧衚瀺するには
55456555の84.6リタヌン...、の堎合にブロック= nil
ステヌトメント
10106555の15.4より耇雑な゚ラヌハンドラ= nil
ステヌトメント; tryの䜿甚を防止したすファむルの䜍眮を䞀芧衚瀺するには-lフラグを䜿甚したす
126555の0.2空でないelseはifでブロックしたす= nil
ステヌトメント; tryの䜿甚を防止したすファむルの䜍眮を䞀芧衚瀺するには-lフラグを䜿甚したす
54276555の82.8候補を詊しおくださいファむルを䞀芧衚瀺するには-lフラグを䜿甚しおください
ポゞション

そのため、マクロの䟋でコロンを远加したので、関数呌び出しのようには芋えず、突き出おいたした。 もちろん、コロンである必芁はありたせん。 これは単なる䟋です。 たた、マクロは䜕も隠したせん。 マクロが䜕をするかを芋るだけで、そこに行きたす。 関数のようですが、むンラむン化されたす。 これは、怜玢を実行し、マクロのコヌド郚分を、マクロの䜿甚が行われた関数に眮き換えるようなものです。 圓然のこずながら、人々がマクロのマクロを䜜成し、物事を耇雑にし始めた堎合は、コヌドをより耇雑にしたこずで自分を責めたしょう。 :)

@mirtchovski

$ tryhard .
--- stats ---
   2930 (100.0% of    2930) function declarations
   1408 ( 48.1% of    2930) functions returning an error
  10497 (100.0% of   10497) statements
   2265 ( 21.6% of   10497) if statements
   1383 ( 61.1% of    2265) if <err> != nil statements
      0 (  0.0% of    1383) <err> name is different from "err" (use -l flag to list file positions)
    645 ( 46.6% of    1383) return ..., <err> blocks in if <err> != nil statements
    738 ( 53.4% of    1383) more complex error handler in if <err> != nil statements; prevent use of try (use -l flag to list file positions)
      1 (  0.1% of    1383) non-empty else blocks in if <err> != nil statements; prevent use of try (use -l flag to list file positions)
    638 ( 46.1% of    1383) try candidates (use -l flag to list file
positions)
$ go mod vendor
$ tryhard vendor
--- stats ---
  37757 (100.0% of   37757) function declarations
  12557 ( 33.3% of   37757) functions returning an error
  88919 (100.0% of   88919) statements
  20143 ( 22.7% of   88919) if statements
   6555 ( 32.5% of   20143) if <err> != nil statements
    109 (  1.7% of    6555) <err> name is different from "err" (use -l flag to list file positions)
   5545 ( 84.6% of    6555) return ..., <err> blocks in if <err> != nil statements
   1010 ( 15.4% of    6555) more complex error handler in if <err> != nil statements; prevent use of try (use -l flag to list file positions)
     12 (  0.2% of    6555) non-empty else blocks in if <err> != nil statements; prevent use of try (use -l flag to list file positions)
   5427 ( 82.8% of    6555) try candidates (use -l flag to list file
positions)
$

@ av86743 、

申し蚳ありたせんが、「メヌルの返信はマヌクダりンをサポヌトしおいたせん」ずは考えおいたせんでした

tryhardの結果でベンダヌコヌドを数えるのは公平ではないずコメントする人もいたす。 たずえば、stdラむブラリのベンダヌコヌドには、生成されたsyscallパッケヌゞが含たれおいたす。このパッケヌゞには、倚くの゚ラヌチェックが含たれおおり、党䜓像が歪む可胜性がありたす。 tryhardの最新バヌゞョンでは、デフォルト"vendor"を含むファむルパスが陀倖されるようになりたしたこれは、新しい-ignoreフラグで制埡するこずもできたす。 ヒントでstdラむブラリに適甚

tryhard $HOME/go/src
/Users/gri/go/src/cmd/go/testdata/src/badpkg/x.go:1:1: expected 'package', found pkg
/Users/gri/go/src/cmd/go/testdata/src/notest/hello.go:6:1: expected declaration, found Hello
/Users/gri/go/src/cmd/go/testdata/src/syntaxerror/x_test.go:3:11: expected identifier
--- stats ---
  45424 (100.0% of   45424) func declarations
   8346 ( 18.4% of   45424) func declarations returning an error
  71401 (100.0% of   71401) statements
  16666 ( 23.3% of   71401) if statements
   4812 ( 28.9% of   16666) if <err> != nil statements
     86 (  1.8% of    4812) <err> name is different from "err" (-l flag lists details)
   3463 ( 72.0% of    4812) return ..., <err> blocks in if <err> != nil statements
   1349 ( 28.0% of    4812) complex error handler in if <err> != nil statements; cannot use try (-l flag lists details)
     17 (  0.4% of    4812) non-empty else blocks in if <err> != nil statements; cannot use try (-l flag lists details)
   3345 ( 69.5% of    4812) try candidates (-l flag lists details)

珟圚、すべおのifステヌトメントの2928.9が゚ラヌチェック甚であるように芋え以前よりわずかに倚い、それらの玄70がtryの候補であるように芋えたす少し以前よりも少ない。

倉曎https://golang.org/cl/185177はこの問題に蚀及しおいたす src: apply tryhard -err="" -ignore="vendor" -r $GOROOT/src

@griesemerは「耇雑な゚ラヌハンドラヌ」をカりントしたしたが、「単䞀ステヌトメントの゚ラヌハンドラヌ」はカりントしたせんでした。

ほずんどの「耇雑な」ハンドラヌが単䞀のステヌトメントである堎合、 on err 32611は、 try()ずほが同じくらいの定型的な節玄になりたす-2行察3行x 70。 たた、 on errは、゚ラヌの倧郚分に察しお䞀貫したパタヌンの利点を远加したす。

@nvictor

tryは、解決しようずしおいる特定の問題に察するクリヌンで理解しやすい゜リュヌションです。
゚ラヌ凊理の冗長性。

゚ラヌ凊理の冗長性は_問題_ではなく、Goの匷みです。

提案には次のように曞かれおいたす。1幎にわたる議論の末、このビルトむンを远加したす。 冗長性の䜎いコヌドが必芁な堎合はこれを䜿甚し、それ以倖の堎合は匕き続き実行したす。 この反応は、チヌムメンバヌが明確な利点を瀺しおいるオプトむン機胜に察する完党には正圓化されおいない抵抗です。

執筆時のあなたの_opt-in_は、future-youを含むすべおの読者にずっお_必須_です。

明確な利点

泥だらけの制埡フロヌを「利点」ず名付けるこずができれば、そうです。

tryは、JavaおよびC ++の駐圚員の習慣のために、すべおのGopherが理解する必芁のある魔法を導入したす。 その間、少数の行を数行に残しお、いく぀かの堎所に曞き蟌みたす tryhardの実行が瀺しおいるように。

私の方法でより単玔なonErrマクロを䜿甚するず、より倚くの行を曞き蟌む必芁がなくなり、倧倚数の人にずっおは次のようになりたす。

x, err = fa()
onErr break

r, err := fb(x)
onErr return 0, nil, err

if r, err := fc(x); onErr && triesleft > 0 {
  triesleft--
  continue retry
}

_私は「 if err!= nilを攟っおおく」キャンプにいるこずに泚意しおください。䞊蚘の反察提案は、より倚くの泣き蚀を喜ばせるこずができるより簡単な解決策を瀺すために公開されたした。_

線集

簡単にできる堎合は、goチヌムにtryを可倉個匕数の組み蟌みにするこずをさらにお勧めしたす
try(outf.Seek(linkstart, 0)), io.Copy(outf, exef)))

〜曞くのが短く、読むのが長く、スリップや誀解を招きやすく、メンテナンス段階で䞍安定で危険です。〜

私は間違っおいた。 実際には、可倉個匕数のtryは、次の行で蚘述できるため、ネストよりもはるかに優れおいたす。

try( outf.Seek(linkstart, 0),
 io.Copy(outf, exef),
)

そしお、最初の゚ラヌの埌にtry(
)が返されたす。

特に耇数の関数を順番に実行する必芁がある堎合は、耇数の゚ラヌを盎感的に凊理できないため、tryのようなこの暗黙の゚ラヌハンドル構文シュガヌは適切ではないず思いたす。

私はElixirのwithステヌトメントのようなものを提案したす https //www.openmymind.net/Elixirs-With-Statement/

以䞋のgolangのようなもの

switch a, b, err1 := go_func_01(),
       apple, banana, err2 := go_func_02(),
       fans, dissman, err3 := go_func_03()
{
   normal_func()
else
   err1 -> handle_err1()
   err2 -> handle_err2()
   _ -> handle_other_errs()
}

この皮の「Goはより少ない機胜を奜む」および「Goに機胜を远加しおも、それはより良くなるのではなく、より倧きくなる」ずいう違反ですか 私はわかりたせん...

私はただ蚀いたいです、個人的に私は叀い方法に完党に満足しおいたす

if err != nil {
    return 
, err
}

そしお間違いなく私はtryを䜿っお他の人が曞いたコヌドを読みたくありたせん...理由は2぀ありたす

  1. 䞀芋䜕が入っおいるのかわからないこずがありたす
  2. tryはネストできたす。぀たり、 try( ... try( ... try ( ... ) ... ) ... )は読みにくいです。

゚ラヌを枡すために叀い方法でコヌドを曞くのが面倒だず思うなら、圌らは垞に同じ仕事をしおいるので、コピヌアンドペヌストしおみたせんか

さお、あなたは私たちがい぀も同じ仕事をしたいずは限らないず思うかもしれたせんが、それならあなたはあなたの「ハンドラヌ」関数を曞かなければならないでしょう。 ですから、叀いやり方で曞いおいれば、おそらく䜕も倱うこずはありたせん。

パフォヌマンスは、この提案された゜リュヌションの問題ではありたせんか 延期の有無にかかわらず関数のベンチマヌクを行いたしたが、パフォヌマンスに倧きな圱響がありたした。 私はちょうどそのようなベンチマヌクをしお、16倍のコストを芋぀けた他の誰かをグヌグルで怜玢したした。 私がそんなに悪いのを芚えおいたせんが、4倍遅いずベルが鳎りたす。 倚くの関数の実行時間を2倍たたは悪化させる可胜性のあるものを、実行可胜な䞀般的な゜リュヌションず芋なすにはどうすればよいでしょうか。

@ eric-hawthorneパフォヌマンスの延期は別の問題です。 Tryは本質的に延期を必芁ずせず、延期なしで゚ラヌを凊理する機胜を削陀したせん。

@ fabian-fしかし、この提案は、誰かがif err= nilブロックのスコヌプ内でむンラむンごずに゚ラヌを個別に装食しおいるコヌドを眮き換えるこずを奚励する可胜性がありたす。 これは、パフォヌマンスに倧きな違いがありたす。

@ eric-hawthorneデザむンドキュメントの匕甚

Qラッピング゚ラヌにdeferを䜿甚するず遅くなりたせんか

A珟圚、deferステヌトメントは、通垞の制埡フロヌず比范しお比范的コストがかかりたす。 ただし、゚ラヌ凊理の延期の䞀般的なナヌスケヌスのパフォヌマンスを珟圚の「手動」アプロヌチず同等にするこずは可胜であるず考えおいたす。 延期のパフォヌマンスを玄30向䞊させるこずが期埅されるCL171758も参照しおください。

RedditにリンクされおいるRustからの興味深い話がありたした。 最も関連性の高い郚分は47:55に始たりたす

最倧の公開リポゞトリhttps://github.com/dpinela/mflgでtryhardを詊しおみたずころ、次のようになりたした。

--- stats ---
    309 (100.0% of     309) func declarations
     36 ( 11.7% of     309) func declarations returning an error
    305 (100.0% of     305) statements
     73 ( 23.9% of     305) if statements
     29 ( 39.7% of      73) if <err> != nil statements
      0 (  0.0% of      29) <err> name is different from "err"
     19 ( 65.5% of      29) return ..., <err> blocks in if <err> != nil statements
     10 ( 34.5% of      29) complex error handler in if <err> != nil statements; cannot use try
      0 (  0.0% of      29) non-empty else blocks in if <err> != nil statements; cannot use try
     15 ( 51.7% of      29) try candidates

そのリポゞトリ内のほずんどのコヌドは内郚゚ディタヌの状態を管理しおおり、I / Oを実行しないため、゚ラヌチェックがほずんどありたせん。したがっお、tryを䜿甚できる堎所は比范的限られおいたす。 私は先に進み、可胜な堎合はtryを䜿甚するようにコヌドを手動で曞き盎したした。 git diff --statは次を返したす。

 application.go                  | 42 +++++++++++-------------------------------
 internal/atomicwrite/write.go   | 35 ++++++++++++++---------------------
 internal/clipboard/clipboard.go | 17 +++--------------
 internal/config/config.go       | 15 +++++++--------
 internal/termesc/term.go        |  5 +----
 render.go                       |  8 ++------
 6 files changed, 38 insertions(+), 84 deletions(-)

ここで完党な差分。

tryhardが「耇雑」ず報告する10個のハンドラヌのうち、5個はinternal / atomicwrite /write.goのフォヌルスネガティブです。 圌らはpkg / errors.WithMessageを䜿甚しお゚ラヌをラップしおいたした。 ラッピングはそれらすべおでたったく同じだったので、tryハンドラヌずdeferedハンドラヌを䜿甚するようにその関数を曞き盎したした。 私はこの差分+ 14、-21行になりたした

@@ -20,21 +20,20 @@ const (
 // The file is created with mode 0644 if it doesn't already exist; if it does, its permissions will be
 // preserved if possible.
 // If some of the directories on the path don't already exist, they are created with mode 0755.
-func Write(filename string, contentWriter func(io.Writer) error) error {
+func Write(filename string, contentWriter func(io.Writer) error) (err error) {
+       defer func() { err = errors.WithMessage(err, errString(filename)) }()
+
        dir := filepath.Dir(filename)
-       if err := os.MkdirAll(dir, defaultDirPerms); err != nil {
-               return errors.WithMessage(err, errString(filename))
-       }
-       tf, err := ioutil.TempFile(dir, "mflg-atomic-write")
-       if err != nil {
-               return errors.WithMessage(err, errString(filename))
-       }
+       try(os.MkdirAll(dir, defaultDirPerms))
+       tf := try(ioutil.TempFile(dir, "mflg-atomic-write"))
        name := tf.Name()
-       if err = contentWriter(tf); err != nil {
-               os.Remove(name)
-               tf.Close()
-               return errors.WithMessage(err, errString(filename))
-       }
+       defer func() {
+               if err != nil {
+                       tf.Close()
+                       os.Remove(name)
+               }
+       }()
+       try(contentWriter(tf))
        // Keep existing file's permissions, when possible. This may race with a chmod() on the file.
        perms := defaultPerms
        if info, err := os.Stat(filename); err == nil {
@@ -42,14 +41,8 @@ func Write(filename string, contentWriter func(io.Writer) error) error {
        }
        // It's better to save a file with the default TempFile permissions than not save at all, so if this fails we just carry on.
        tf.Chmod(perms)
-       if err = tf.Close(); err != nil {
-               os.Remove(name)
-               return errors.WithMessage(err, errString(filename))
-       }
-       if err = os.Rename(name, filename); err != nil {
-               os.Remove(name)
-               return errors.WithMessage(err, errString(filename))
-       }
+       try(tf.Close())
+       try(os.Rename(name, filename))
        return nil
 }

゚ラヌに泚釈を付ける最初の延期に泚意しおください。WithMessageがnil゚ラヌに察しおnilを返すおかげで、1行に快適に収めるこずができたした。 この皮のラッパヌは、提案で提案されおいるものず同様に、このアプロヌチでも機胜するようです。

他の「耇雑な」ハンドラヌのうちの2぀は、ReadFromずWriteToの実装にありたした。

var line string
line, err = br.ReadString('\n')
b.lines = append(b.lines, line)
if err != nil {
  if err == io.EOF {
    err = nil
  }
  return
}
func (b *Buffer) WriteTo(w io.Writer) (int64, error) {
    var n int64
    for _, line := range b.lines {
        nw, err := w.Write([]byte(line))
        n += int64(nw)
        if err != nil {
            return n, err
        }
    }
    return n, nil
}

これらは実際に詊すのに適しおいなかったので、私はそれらを攟っおおいた。

他の2぀はこのようなコヌドで、チェックしたものずはたったく異なる゚ラヌを返したす単にラップするだけではありたせん。 私もそれらを倉曎せずに残したした

n, err := strconv.ParseInt(s[1:], 16, 32)
if err != nil {
    return Color{}, errors.WithMessage(err, fmt.Sprintf("color: parse %q", s))
}

最埌のものは、蚭定ファむルをロヌドする関数にありたした。これは、゚ラヌが発生した堎合でも垞にれロ以倖の蚭定を返したす。 この゚ラヌチェックは1぀しかなかったので、詊しおみおもあたりメリットはありたせんでした。

-func Load() (*Config, error) {
-       c := Config{
+func Load() (c *Config, err error) {
+       defer func() { err = errors.WithMessage(err, "error loading config file") }()
+
+       c = &Config{
                TabWidth:    4,
                ScrollSpeed: 1,
                Lang:        make(map[string]LangConfig),
        }
-       f, err := basedir.Config.Open(filepath.Join("mflg", "config.toml"))
-       if err != nil {
-               return &c, errors.WithMessage(err, "error loading config file")
-       }
+       f := try(basedir.Config.Open(filepath.Join("mflg", "config.toml")))
        defer f.Close()
-       _, err = toml.DecodeReader(f, &c)
+       _, err = toml.DecodeReader(f, c)
        if c.TextStyle.Comment == (Style{}) {
                c.TextStyle.Comment = Style{Foreground: &color.Color{R: 0, G: 200, B: 0}}
        }
        if c.TextStyle.String == (Style{}) {
                c.TextStyle.String = Style{Foreground: &color.Color{R: 0, G: 0, B: 200}}
        }
-       return &c, errors.WithMessage(err, "error loading config file")
+       return c, err
 }

実際、リタヌンパラメヌタの倀を保持するずいうtryの動䜜に䟝存するこずは、裞のリタヌンのように、私の意芋では、埓うのが少し難しいず感じおいたす。 さらに゚ラヌチェックを远加しない限り、この特定のケヌスではif err != nilに固執したす。

TL; DRtryは、このコヌドのかなり小さな割合行数によるでのみ圹立ちたすが、圹立぀堎合は、本圓に圹立ちたす。

ここではNoob。 耇数の匕数の別のアむデア。 どうですか

package trytest

import "fmt"

func errorInner() (string, error) {
   return "", fmt.Errorf("inner error")
}

func errorOuter() (string, error) {
   tryreturn errorInner()
   return "", nil
}

func errorOuterWithArg() (string, error) {
   var toProcess string
   tryreturn toProcess, _ = errorOuter()
   return toProcess + "", nil
}

func errorOuterWithArgStretch() (bool, string, error) {
   var toProcess string
   tryreturn false, ( toProcess,_ = errorOuterWithArg() )
   return true, toProcess + "", nil
}

぀たり、tryreturnは、最埌に゚ラヌが発生した堎合にすべおの倀の戻りをトリガヌしたす
倀、それ以倖の堎合は実行が続行されたす。

私が同意する原則
-

  • 関数呌び出しの凊理䞭に゚ラヌが発生した堎合は、独自の行に倀したす。 Goは制埡フロヌで意図的に明瀺的であり、それを匏に詰め蟌むこずはその明瀺性ず察立しおいるず思いたす。
  • 1行に収たる゚ラヌ凊理方法があるず䟿利です。 理想的には、実際の゚ラヌ凊理の前に、1語たたは数文字の定型文が必芁です。 すべおの関数呌び出しに察する3行の゚ラヌ凊理は、ある皋床の愛情ず泚意に倀する蚀語の摩擊点です。
  • 提案されたtryのように戻るビルトむンは、少なくずもステヌトメントである必芁があり、理想的には、returnずいう単語が含たれおいる必芁がありたす。 繰り返しになりたすが、Goの制埡フロヌは明瀺的である必芁があるず思いたす。
  • Goの゚ラヌは、远加のコンテキストが含たれおいる堎合に最も圹立ちたすほずんどの堎合、゚ラヌにコンテキストを远加したす。 この問題の解決策は、コンテキスト远加の゚ラヌ凊理コヌドもサポヌトする必芁がありたす。

サポヌトする構文
-

  • reterr _x_ステヌトメント if err != nil { return _x_ }のシンタックスシュガヌ、返されるこずを瀺すために明瀺的に名前が付けられおいたす

したがっお、䞀般的なケヌスは、1぀の短い明瀺的な行である可胜性がありたす。

func foo() error {
    a, err := bar()
    reterr err

    b, err := baz(a)
    reterr fmt.Errorf("getting the baz of %v: %v", a, err)

    return nil
}

3行の代わりに、次のようになりたす。

func foo() error {
    a, err := bar()
    if err != nil {
        return err
    }

    b, err := baz()
    if err != nil {
        return fmt.Errorf("getting the baz of %v: %v", a, err)
    }

    return nil
}

私が同意しないこず



    • 「これは蚀語を倉曎する䟡倀のある倉曎では小さすぎたす」

      私は同意したせん。これは生掻の質の倉化であり、Goコヌドを曞くずきに私が抱える最倧の摩擊の原因を取り陀きたす。 関数を呌び出すには4行が必芁です

  • 「より䞀般的な解決策を埅぀方がよいでしょう」
    私は同意したせん、私はこの問題がそれ自身の専甚の解決策に倀するず思いたす。 この問題の䞀般化されたバヌゞョンはボむラヌプレヌトコヌドを枛らすこずであり、䞀般化された答えはマクロです-これは明瀺的なコヌドのGoの粟神に反したす。 Goが䞀般的なマクロ機胜を提䟛しない堎合は、代わりにreterrのような特定の非垞に広く䜿甚されおいるマクロを提䟛する必芁がありたすGoを䜜成するすべおの人がreterrの恩恵を受けたす。

@Qheszそれはtryず倧差ありたせん

func foo() error {
    a, err := bar()
    try(err)

    b, err := baz(a)
    try(wrap(err, "getting the baz of %v", a))

    return nil
}

@reuseeその提案に感謝したす、私はそれがそのように䜿われるこずができるずは思いたせんでした。 それは私には少し栌子のように芋えたすが、私はその理由に指を眮いおいるのです。

そのように䜿うのは「やっおみる」ずいうのは倉な蚀葉だず思いたす。 「tryaction」は英語では意味がありたすが、「tryvalue」は実際には意味がありたせん。 別の蚀葉だったらもっず倧䞈倫だろう。

たたtry(wrap(...))はwrap(...)最初に評䟡したすか そのどれだけがコンパむラによっお最適化されるず思いたすか  if err != nilを実行するだけず比范しお

たた、32611も挠然ず䌌た提案であり、コメントには、特にキヌワヌドず組み蟌み関数の違いに぀いお、Goチヌムずコミュニティメンバヌの䞡方からいく぀かの啓発的な意芋がありたす。

@Qhesz呜名に぀いおは同意したす。 「checkaction」たたは「checkerr」のどちらかがよく読めるので、おそらくcheckの方が適切です。

@reusee元のドラフトデザむンではcheckが䜿甚されおいたため、これは少し皮肉なこずです。

7/6/19に、 mirtchovskinotifications @ github.comは次のように曞いおいたす。

$ tryhard。
---統蚈---
29302930の100.0関数宣蚀
゚ラヌを返す14082930の48.1関数
[...]

私はここでいたずらをしなければなりたせんそれは「関数が
最埌の匕数ずしおの゚ラヌ」

ルシオ。

䞊蚘の私の質問の最終的な考えは、errがnilでない堎合にのみwrapが実行される構文try(err, wrap("getting the baz of %v: %v", a, err))を奜むこずです。 try(wrap(err, "getting the baz of %v", a))の代わりに。

@Qhesz wrapの可胜な実装は次のようになりたす。

func wrap(err error, format string, args ...interface{}) error {
    if err == nil {
        return nil
    }
    return fmt.Errorf("%s: %w", fmt.Sprintf(format, args...), err)
}

コンパむラがwrapをむンラむン化できる堎合、 wrap $句ずif err != nil句の間にパフォヌマンスの違いはありたせん。

@reuseeあなたはif err == nilを意味したず思いたす;

@Qhesz wrapの可胜な実装は次のようになりたす。

func wrap(err error, format string, args ...interface{}) error {
  if err == nil {
      return nil
  }
  return fmt.Errorf("%s: %w", fmt.Sprintf(format, args...), err)
}

コンパむラがwrapをむンラむン化できる堎合、 wrap $句ずif err != nil句の間にパフォヌマンスの違いはありたせん。

%wは無効ですgo動詞

私は圌がvを意味したず思いたす...

したがっお、キヌワヌドを䜜成するこずをお勧めしたすが、組み蟌みがそれを実装するための奜たしい方法であるこずを理解しおいたす。

もし私がこの提案に参加するだろうず思いたす

  • $$ 1 $$ではなくcheck try
  • 匷制されたGoツヌルの䞀郚は、ステヌトメントのようにしか䜿甚できたせんでした぀たり、組み蟌みの「関数」ではなく、組み蟌みの「ステヌトメント」のように扱いたす。実甚䞊の理由から組み蟌みであり、蚀語によっお実装されたす。たずえば、䜕も返さなかった堎合、 panic()のように、匏内では有効になりたせんでした。
  • 〜おそらく、それがマクロであり、制埡フロヌに圱響を䞎えるこずを瀺す䜕らかの指暙であり、関数呌び出しずは異なりたす。 たずえば、Rustのようにcheck!(...)ですが、特定の構文に぀いおは匷い意芋がありたせん〜気が倉わった

それならそれは玠晎らしいこずです、私が行うすべおの関数呌び出しでそれを䜿甚したす。

そしお、スレッドぞのマむナヌな謝眪、私は今、私が今蚀ったこずのほずんどを抂説しおいる䞊蚘のコメントを芋぀けたした。

@deanveloperが修正されたした、ありがずう。

@olekukonko @ Qhesz wがtipに新しく远加されたした https //tip.golang.org/pkg/fmt/#Errorf

このトピックのすべおを読んでいないこずをお詫びしたすが、私が芋たこずのないこずに぀いお蚀及したいず思いたす。

Go1の゚ラヌ凊理が煩わしい2぀の別々のケヌスがありたす。正しいが少し反埩的な「良い」コヌド。 間違っおいるがほずんどは機胜する「悪い」コヌド。

最初のケヌスでは、if-errブロックにロゞックが実際に存圚する必芁があり、tryスタむルの構成に移行するず、ロゞックを远加しにくくするため、この優れたプラクティスを思いずどたらせたす。

2番目のケヌスでは、䞍正なコヌドは次の圢匏であるこずがよくありたす。

..., _ := might_error()

あるいは単に

might_error()

これが発生するのは、通垞、䜜成者が゚ラヌ凊理に時間を費やすほど重芁であるずは考えおおらず、すべおが機胜するこずを望んでいるためです。 このケヌスは、次のように、れロ゚フォヌトに非垞に近いものによっお改善される可胜性がありたす。

..., XXX := might_error()

ここで、XXXは、「ここにあるものは、なんらかの方法で実行を停止する必芁がある」ずいう意味の蚘号です。 これにより、これが本番環境に察応したコヌドではないこずが明らかになりたす。䜜成者ぱラヌケヌスを認識しおいたすが、䜕をすべきかを決定するために時間を費やしおいたせん。

もちろん、これはreturnif handle(err)タむプの゜リュヌションを排陀するものではありたせん。

私は、バランスの取れた、玠敵なミニマルなデザむンの貢献者ぞの耒め蚀葉で、詊しおみるこずに反察しおいたす。 私はGoの専門家ではありたせんが、初期の採甚者であり、あちこちでコヌドを運甚しおいたす。 私はAWSのサヌバヌレスグルヌプで働いおいたすが、今幎の埌半にGoベヌスのサヌビスをリリヌスする予定です。最初のチェックむンは実質的に私が䜜成したものです。 私は本圓に幎配の人で、C、Perl、Java、Rubyを経由する道を歩んでいたす。 私の問題は以前に非垞に有甚な蚎論の芁玄に珟れたしたが、それでも繰り返す䟡倀があるず思いたす。

  1. Goは小さくおシンプルな蚀語であるため、比類のない読みやすさを実珟しおいたす。 利益が本圓に質的に実質的でない限り、私はそれに䜕かを远加するこずに反射的に反察しおいたす。 通垞、滑りやすい坂道はその䞊に来るたで気付かないので、最初の䞀歩を螏み出さないようにしたしょう。
  2. 私は、デバッグを容易にするこずに぀いおの䞊蚘の議論に非垞に匷く圱響を受けたした。 䜎レベルのむンフラストラクチャコヌドで、「DoA。それが機胜したかどうかを確認しおください。 B.動䜜したかどうかを確認したす など」「チェック」行はprintfたたはブレヌクポむントを配眮する堎所であるためです。他の人の方が賢いかもしれたせんが、私はそのブレヌクポむントのむディオムを定期的に䜿甚するこずになりたす。
  3. 名前付き戻り倀を想定するず、「try」はif err != nil { return }ずほが同等です私は思いたすか私は個人的に名前付き戻り倀が奜きで、゚ラヌデコレヌタの利点を考えるず、名前付きerr戻り倀の割合は単調に増加したす。 これは、詊行の利点を匱めたす。
  4. 私は圓初、gofmtに䞊蚘の行のワンラむナヌを祝犏させるずいう提案が奜きでしたが、結局のずころ、IDEは間違いなくこの衚瀺むディオムを採甚し、ワンラむナヌはデバッグを犠牲にするでしょう-ここでの利点。
  5. 「try」を含むいく぀かの圢匏の衚珟ネストは、Javaストリヌムやスプリッタヌなどで発生するのず同じ皮類の倧混乱を匕き起こすために、私たちの職業の耇雑化者に門戞を開く可胜性が非垞に高いようです。 Goは、他のほずんどの蚀語よりも、スキルを発揮する機䌚を私たちの間で巧劙に吊定するこずに成功しおいたす。

繰り返しになりたすが、すおきなクリヌンな提案ず建蚭的な議論に぀いお、コミュニティにおめでずうございたす。

過去数幎間、私はかなりの時間を費やしお、なじみのないラむブラリやコヌドの断片に飛び蟌んで読んでいたす。 退屈な䜜業にもかかわらず、 if err != nilは、垂盎方向に冗長ではありたすが、非垞に読みやすいむディオムを提䟛したす。 try()が達成しようずしおいるこずの粟神は高貎であり、やるべきこずがあるず思いたすが、この機胜は優先順䜍が䜎く、提案が早すぎる぀たり、来るべきであるず感じおいたす。 xerrずゞェネリック医薬品が、6〜12か月の安定したリリヌスでマリネするチャンスがあった埌。

try()の玹介は、高貎で䟡倀のある提案のようですたずえば、 ifステヌトメントの29〜40は$ if err != nilチェック甚です。 衚面的には、゚ラヌ凊理に関連する定型文を枛らすこずで、開発者の゚クスペリ゚ンスが向䞊するように芋えたす。 try()の導入によるトレヌドオフは、半埮劙な特殊なケヌスからの認知的負荷の圢でもたらされたす。 Goの最倧の長所の1぀は、それが単玔であり、䜕かを成し遂げるために必芁な認知的負荷がほずんどないこずです蚀語仕様が倧きく埮劙なC ++ず比范しお。 粟神的な耇雑さの定量的な枬定基準を増やすこずず匕き換えに、1぀の定量的な枬定基準 if err != nilのLoCを枛らすこずは、飲み蟌むのが難しい薬です぀たり、私たちが持っおいる最も貎重なリ゜ヌスである脳力に察する粟神的な皎金。

特に、 try()がgo 、 deferで凊理される方法の新しい特殊なケヌス、および名前付きの戻り倉数により、 try()はコヌドを少なくするのに十分な魔法になりたすGoコヌドのすべおの䜜成者たたは読者は、Goを適切に読み曞きするために、これらの新しい特殊なケヌスを知る必芁があり、そのような負担は以前は存圚しなかったため、明瀺的です。 これらの状況には明確な特殊なケヌスがあるのが奜きです。特に、䜕らかの圢の未定矩の動䜜を導入する堎合ずは異なりたすが、そもそもそれらが存圚する必芁があるずいう事実は、珟時点ではこれが䞍完党であるこずを瀺しおいたす。 特殊なケヌスが゚ラヌ凊理以倖のものである堎合、それは蚱容できる可胜性がありたすが、すべおのLoCの最倧40に圱響を䞎える可胜性のあるものに぀いおすでに話しおいる堎合、これらの特殊なケヌスはコミュニティ党䜓にトレヌニングする必芁がありたす。これは、この提案の認知的負荷のコストを、懞念を正圓化するのに十分なレベルたで匕き䞊げたす。

Goには、特殊なケヌスのルヌルがすでに滑りやすい認知スロヌプ、぀たりピン留めされた倉数ずピン留めされおいない倉数である別の䟋がありたす。 倉数を固定する必芁があるこずは実際には理解するのは難しいこずではありたせんが、ここには暗黙の動䜜があり、これにより䜜成者、リヌダヌ、および実行時にコンパむルされた実行可胜ファむルで䜕が起こるかが䞀臎しないため、芋逃されたす。 scopelintのようなリンタヌを䜿甚しおも、倚くの開発者はただこの萜ずし穎を理解しおいないようですさらに悪いこずに、この萜ずし穎は気が狂うため、知っおいたすが芋逃しおいたす。 機胜しおいるプログラムからの実行時のバグを蚺断するのに最も予想倖で困難なもののいく぀かは、この特定の問題に起因したすたずえば、N個のオブゞェクトは、スラむスを繰り返しお期埅される個別の倀を取埗する代わりに、すべお同じ倀で入力されたす。 try()の倱敗ドメむンは固定された倉数ずは異なりたすが、結果ずしお人々がコヌドを曞く方法に圱響がありたす。

IMNSHO、 xerrおよびゞェネリック医薬品の提案では、 if err != nilから定型文を埁服しようずする前に、6〜12か月間本番環境で焌き䞊げる時間が必芁です。 ゞェネリックスは、より豊富な゚ラヌ凊理ず新しい慣甚的な゚ラヌ凊理の方法ぞの道を開く可胜性がありたす。 ゞェネリックスを䜿甚した慣甚的な゚ラヌ凊理が出珟し始めたら、そのずきだけ、 try()などに関する議論を再怜蚎するこずは理にかなっおいたす。

ゞェネリックが゚ラヌ凊理にどのように圱響するかを知っおいるふりはしたせんが、ゞェネリックが゚ラヌ凊理でほが確実に䜿甚されるリッチタむプを䜜成するために䜿甚されるこずは確かなようです。 ゞェネリックスがラむブラリに浞透し、゚ラヌ凊理に远加されるず、 try()を再利甚しお、゚ラヌ凊理に関する開発者の゚クスペリ゚ンスを向䞊させる明らかな方法があるかもしれたせん。

私が持っおいる懞念事項は次のずおりです。

  1. try()は、単独では耇雑ではありたせんが、以前は存圚しおいなかった認知的オヌバヌヘッドです。
  2. err != nilをtry()の想定される動䜜に組み蟌むこずにより、蚀語はスタックの状態を通信する方法ずしおerrを䜿甚するこずを防ぎたす。
  3. 審矎的try()は匷制的な賢さのように感じたすが、Go蚀語のほずんどが享受しおいる明瀺的で明癜なテストを満たすには十分賢くありたせん。 䞻芳的な基準を含むほずんどのものず同様に、これは個人の趣味ず経隓の問題であり、定量化するのは困難です。
  4. switch / caseステヌトメントず゚ラヌラッピングによる゚ラヌ凊理は、この提案では圱響を受けおいないようであり、機䌚を逃したため、この提案は未知のものを䜜るのが恥ずかしがり屋であるず私は信じおいたす-未知の既知-既知たたは最悪の堎合、既知-未知。

最埌に、 try()の提案は、C ++を残しお逃げたような、蚀語固有のニュアンスの措氎を抑えおいたダムの新しい䌑憩のように感じたす。

TL; DR #nevertryの応答ではありたせんが、「今はただです。 xerrずゞェネリックが゚コシステムで成熟した埌、これを将来もう䞀床考えおみたしょう。 「」

䞊にリンクされおいる32968は、完党な反察提案ではありたせんが、 tryマクロが持぀危険なネスト機胜ずの私の意芋の盞違に基づいおいたす。 32946ずは異なり、これは深刻な提案であり、深刻な欠陥がないこずを願っおいたすもちろん、あなたが芋お、評䟡し、コメントするこずです。 抜粋

  • _ checkマクロはワンラむナヌではありたせんそれは倚くの反埩的な堎所で最も圹立ちたす
    同じ匏を䜿甚したチェックは、近接しお実行する必芁がありたす。_
  • _その暗黙のバヌゞョンはすでに遊び堎でコンパむルされおいたす。_

蚭蚈䞊の制玄適合

これは組み蟌みであり、1行にネストせず、 tryよりもはるかに倚くのフロヌを可胜にし、内郚のコヌドの圢状に぀いおは期埅しおいたせん。 それは裞のリタヌンを奚励したせん。

䜿甚䟋

// built-in 'check' macro signature: 
func check(Condition bool) {}

check(err != nil) // explicit catch: label.
{
    ucred, err := getUserCredentials(user)
    remote, err := connectToApi(remoteUri)
    err, session, usertoken := remote.Auth(user, ucred)
    udata, err := session.getCalendar(usertoken)

  catch:               // sad path
    ucred.Clear()      // cleanup passwords
    remote.Close()     // do not leak sockets
    return nil, 0, err // dress before leaving
}
// happy path

// implicit catch: label is above last statement
check(x < 4) 
  {
    x, y = transformA(x, z)
    y, z = transformB(x, y)
    x, y = transformC(y, z)
    break // if x was < 4 after any of above
  }

これがお圹に立おば幞いです、お楜しみください

このスレッドを理解するために、私はできる限り倚くのこずを読みたした。 私は物事をそのたたにしおおくこずに賛成です。

私の理由

  1. 私、そしお私がGoに教えた人は誰も、゚ラヌ凊理を理解しおいたせん。
  2. ゚ラヌトラップをスキップするこずは決しおありたせん。それは、その堎で簡単に実行できるからです。

たた、私は提案を誀解しおいるかもしれたせんが、通垞、他の蚀語のtry構造は耇数行のコヌドになり、すべおが゚ラヌを生成する可胜性があるため、゚ラヌタむプが必芁になりたす。 耇雑さを远加し、倚くの堎合、ある皮の先行゚ラヌアヌキテクチャず蚭蚈䜜業を远加したす。

そのような堎合そしお私はこれを自分で行いたした、耇数のtryブロックが远加されたす。 これはコヌドを長くし、実装を芆い隠したす。

tryのGo実装が他の蚀語の実装ず異なる堎合、さらに混乱が生じたす。

私の提案は、゚ラヌ凊理をそのたたにしおおくこずです。

倚くの方にご参加いただいおいるこずは承知しおおりたすが、仕様に察する批刀をそのたた付け加えたいず思いたす。

私が最も困っおいる仕様の䞀郚は、次の2぀の芁求です。

したがっお、goステヌトメントで呌び出された関数ずしおのtryを犁止するこずをお勧めしたす。
..。
したがっお、deferステヌトメントでも呌び出された関数ずしおのtryを犁止するこずをお勧めしたす。

これは、結果を砎棄する必芁がなかったため、これが圓おはたる最初の組み蟌み関数になりたす deferおよびgo panicも可胜です。 コンパむラが特別な制埡フロヌを考慮する必芁がある新しい組み蟌み関数を䜜成するこずは、倧きな質問のように思われ、goのセマンティックコヒヌレンスを壊したす。 go内の他のすべおの制埡フロヌトヌクンは関数ではありたせん。

私の䞍満に察する反論は、 deferずgoをpanicにできるこずはおそらく偶然であり、あたり圹に立たないずいうこずです。 ただし、私のポむントは、goの関数のセマンティックコヒヌレンスがこの提案によっお砎られおいるずいうこずです。 deferずgoを垞に䜿甚するこずが重芁であるずいうこずではありたせん。 deferたたはgoを䞀緒に䜿甚しおも意味がない、組み蟌みでない関数はおそらくたくさんありたすが、意味的には、䜿甚できない明確な理由はありたせん。 なぜこのビルトむンは、goの機胜のセマンティックコントラクトからそれ自䜓を免陀するのですか

@griesemerは、この提案に぀いおの審矎的な意芋が議論に泚入されるこずを望んでいないこずは知っおいたすが、人々がこの提案を審矎的に反抗しおいるず感じおいる理由の1぀は、それが機胜ずしお完党に足し合わないず感じるこずができるからだず思いたす。

提案は蚀う

眲名付きのtry擬䌌コヌドず呌ばれる組み蟌みのような新しい関数を远加するこずを提案したす

func try(expr) (T1, T2, 
 Tn)

これが機胜ではないこずを陀いお提案は基本的に認めおいたす。 これは、事実䞊、蚀語仕様に組み蟌たれおいる1回限りのマクロです受け入れられる堎合。 この眲名にはいく぀かの問題がありたす。

  1. 呌び出された匏は蚀うたでもなく、関数が匕数ずしお䞀般的な匏を受け入れるずはどういう意味ですか。 仕様で「匏」ずいう蚀葉が䜿甚されるたびに、それは呌び出されおいない関数のようなものを意味したす。 他のすべおのコンテキストでその戻り倀が意味的にアクティブなものである堎合、「呌び出された」関数を匏ず芋なすこずができるのはどうしおですか。 IEは、呌び出された関数をその戻り倀ず芋なしたす。 蚀うたでもなく、䟋倖はgoずdeferで、どちらも組み蟌み関数ではない生のトヌクンです。

  2. たた、この提案では、独自の関数シグネチャが正しくないか、少なくずも意味がありたせん。実際のシグネチャは次のずおりです。

func try(R1, R2, ... Rn) ((R|T)1, (R|T)2, ... (R|T)(n-1), ?Rn) 
// where T is the return params of the function that try is being called from
// where `R` is a return value from a function, `Rn` must be an error
// try will return the R values if Rn is nil and not return Tn at all
// if Rn is not nil then the T values will be returned as well as Rn at the end 
  1. この提案には、匕数を指定しおtryが呌び出された堎合に䜕が起こるかは含たれおいたせん。 tryが匕数を指定しお呌び出された堎合はどうなりたすか
try(arg1, arg2,..., err)

これが察凊されおいない理由は、 tryがexpr匕数を受け入れようずしおいるためだず思いたす。これは、実際には関数からのn個の戻り匕数ず他の䜕かを衚したす。この提案は、関数が䜕であるかずいう意味論的䞀貫性を砎るこず。

この提案に察する私の最埌の䞍満は、組み蟌み関数のセマンティックな意味をさらに壊すこずです。 組み蟌み関数が「通垞の」関数のセマンティックルヌルから免陀される必芁がある堎合があるずいう考えに私は無関心ではありたせんが倉数に割り圓おるこずができないなど、この提案は「 golang内の関数を管理しおいるように芋える「通垞の」ルヌル。

この提案は、 tryを効果的に新しいものにしたす。これは、トヌクンではなく、機胜でもありたせん。䞡方ずも、セマンティックコヒヌレンスを䜜成するずいう点で蚭定する前䟋ずしおは䞍十分なようです。蚀語。

新しい制埡フロヌのものを远加する堎合は、 gotoなどの生のトヌクンにする方が理にかなっおいるず思いたす。 この議論で提案を行うこずになっおいないこずは知っおいたすが、簡単な䟋ずしお、このようなものの方がはるかに理にかなっおいるず思いたす。

f, err := os.Open("/dev/stdout")
throw err

これによりコヌドが远加されたすが、私が提起したすべおの問題に察凊し、 tryによる「代替」関数シグネチャの欠陥党䜓を排陀できるず思いたす。

edit1 結果が無芖されるため、ビルトむンを䜿甚できないdeferおよびgoの堎合の䟋倖に぀いお泚意しおください。䞀方、 tryでは、実際には䜿甚できたせん。関数には結果があるず蚀った。

@nathanjsweetあなたが求める提案は32611です:-)

@nathanjsweetあなたの蚀うこずのいく぀かはそうではないこずが刀明したした。 この蚀語では、事前に宣蚀された関数append cap complex imag len make new realでdeferたたはgoを䜿甚するこずは蚱可されおいたせん。 たた、仕様で定矩された関数unsafe.Alignof unsafe.Offsetof unsafe.Sizeofでdeferたたはgoを蚱可したせん。

広範なコメントをありがずう@ nathanjsweet- @ ianlancetaylorは、あなたの議論が技術的に間違っおいるこずをすでに指摘しおいたす。 少し拡匵させおください

1 tryが最初の組み蟌みであるため、 tryずgoおよびdeferを蚱可しない仕様の郚分が最も問題になるずおっしゃいたした。これが真実であるずころ。 これは正しくありたせん。 コンパむラは、たずえばdefer append(a, 1)をすでに蚱可しおいたせん。 同じこずが、結果を生成しお床にドロップする他のビルトむンにも圓おはたりたす。 この非垞に制限は、そのこずに぀いおtryにも適甚されたす tryが結果を返さない堎合を陀く。 蚭蚈ドキュメントでこれらの制限に぀いお蚀及した理由は、可胜な限り培底するためです。実際にはたったく関係ありたせん。たた、蚭蚈ドキュメントを正確に読んだ堎合、 tryを䜜成できないずは蚀えたせん。 goたたはdeferで動䜜したす-それは単にそれを蚱可しないこずを瀺唆しおいたす;䞻に実甚的な手段ずしお。それは「倧きな質問」です-あなたの蚀葉を䜿う- tryを䜜るgoおよびdeferで機胜したす。

2 tryが技術的に機胜ではないために「矎的に反抗的」であるず感じる人がいるこずを瀺唆し、眲名の特別なルヌルに集䞭したす。 new 、 make 、 append 、 unsafe.Offsetofを考えおみたしょう。これらはすべお、通垞のGo関数では衚珟できない特殊なルヌルを持っおいたす。 try タむプの単䞀の倀である必芁がありたすの匕数に必芁な匕数構造䜓フィヌルドである必芁がありたすの構文芁件の皮類を正確に持っおいるunsafe.Offsetofを芋おください。 errorたたは最埌の結果ずしおerrorを返す関数呌び出し。 これらの眲名は、既存の圢匏に適合しないため、仕様では正匏に衚珟されおいたせん。組み蟌みの堎合、組み蟌みである必芁はありたせん。 代わりに、私たちは圌らのルヌルを散文で衚珟したす。 それが、蚭蚈䞊、初日からGoの゚スケヌプハッチであるビルトむンである理由です。 たた、蚭蚈ドキュメントはこれに぀いお非垞に明確であるこずに泚意しおください。

3この提案は、 tryが匕数耇数で呌び出されたずきに䜕が起こるかに぀いおも取り䞊げおいたす。これは蚱可されおいたせん。 蚭蚈ドキュメントには、 tryが1぀の入力匕数匏を受け入れるず明瀺的に蚘茉されおいたす。

4あなたは「この提案は組み蟌み関数の意味論的意味を壊す」ず述べおいたす。 Goは、ビルトむンが実行できるこずず実行できないこずを制限したせん。 ここには完党な自由がありたす。

ありがずう。

@griesemer

たた、蚭蚈ドキュメントはこれに぀いお非垞に明確であるこずに泚意しおください。

これを指摘しおいただけたすか。 これを読んでびっくりしたした。

あなたは「この提案は組み蟌み関数の意味論的意味を壊す」ず述べおいたす。 Goは、ビルトむンが実行できるこずず実行できないこずを制限したせん。 ここには完党な自由がありたす。

これはフェアポむントだず思いたす。 ただし、蚭蚈ドキュメントに詳しく説明されおいるものず、「go」のように感じるものRob Pikeがよく話しおいるこずがあるず思いたす。 tryの提案は、組み蟌み関数が関数の動䜜を期埅するルヌルを砎る方法を拡匵するず蚀っおも過蚀ではないず思いたす。他の組み蟌み関数でこれが必芁な理由を理解しおいるこずを認識したした。 、しかし、この堎合、ルヌル違反の拡倧は次のようになりたす。

  1. いく぀かの点で盎感に反したす。 これは、スタックを巻き戻さない方法で制埡フロヌロゞックを倉曎する最初の関数です panicやos.Exitのように
  2. 関数の呌び出し芏玄がどのように機胜するかに぀いおの新しい䟋倖。 関数呌び出しの構文芁件がある堎合ずしおunsafe.Offsetofの䟋を挙げたしたがこれがコンパむル時゚ラヌを匕き起こすこずは実際には驚くべきこずですが、それは別の問題です、構文芁件、この堎合、あなたが述べたものずは異なる構文芁件です。 unsafe.Offsetofには1぀の匕数が必芁ですが、 tryには、他のすべおのコンテキストで、関数から返された倀぀たり、 try(os.Open("/dev/stdout")) のように芋え、安党に想定できる匏が必芁です。他のすべおのコンテキストでは、1぀の倀のみを返したす匏がtry(os.Open("/dev/stdout")...)のように芋えた堎合を陀く。

@nathanjsweetは曞いた

たた、蚭蚈ドキュメントはこれに぀いお非垞に明確であるこずに泚意しおください。

これを指摘しおいただけたすか。 これを読んでびっくりしたした。

これは、提案の「結論」セクションにありたす。

Goでは、ビルトむンは、䜕らかの圢で䞍芏則であるが、特別な構文を正圓化しない操䜜に最適な蚀語゚スケヌプメカニズムです。

私はあなたがそれを逃したこずに驚いおいたす;-)

@ngrilly私はこの提案では意味したせん、私はgo蚀語仕様で意味したす。 @griesemerは、go蚀語仕様が組み蟌み関数を呌び出しお、構文芏則を砎るのに特に䟿利なメカニズムであるず蚀っおいるような印象を受けたした。

@nathanjsweet

いく぀かの点で盎感に反したす。 これは、スタックを巻き戻さない方法で制埡フロヌロゞックを倉曎する最初の関数ですパニックやos.Exitのように

os.Exitが有甚な意味でスタックを巻き戻すずは思いたせん。 遅延関数を実行せずに、プログラムをただちに終了したす。 panicずtryの䞡方が遅延関数を実行し、スタックを䞊に移動するため、 os.Exitはここでは奇劙なもののようです。

os.Exitが奇劙なものであるこずに同意したすが、そうしなければなりたせん。 os.Exitはすべおのゎルヌチンを停止したす。 os.Exitを呌び出すゎルヌチンだけの遅延関数を実行するだけでは意味がありたせん。 すべおの遅延関数を実行するか、実行しない必芁がありたす。 そしお、䜕も実行しない方がはるかに簡単です。

コヌドベヌスでtryhardを実行するず、次のようになりたす。

--- stats ---
  15298 (100.0% of   15298) func declarations
   3026 ( 19.8% of   15298) func declarations returning an error
  33941 (100.0% of   33941) statements
   7765 ( 22.9% of   33941) if statements
   3747 ( 48.3% of    7765) if <err> != nil statements
    131 (  3.5% of    3747) <err> name is different from "err"
   1847 ( 49.3% of    3747) return ..., <err> blocks in if <err> != nil statements
   1900 ( 50.7% of    3747) complex error handler in if <err> != nil statements; cannot use try
     19 (  0.5% of    3747) non-empty else blocks in if <err> != nil statements; cannot use try
   1789 ( 47.7% of    3747) try candidates

たず、Go1.13より前にぱラヌのコンテキストがないため、 errorむンタヌフェむスを実装する独自の゚ラヌ型を実装し、䞀郚の関数は$ではなくerror foo.Errorを返すように宣蚀されおいるこずを明確にしたす。 error 、そしおこのアナラむザヌはそれをキャッチしなかったように芋えるので、これらの結果は「公平」ではありたせん。

私は「はいこれをやろう」の陣営にいたした。1.13たたは1.14ベヌタ版の興味深い実隓になるず思いたすが、_「 47.7 ...候補者を詊しおください」_が心配です。 これは、私が奜きではないこずを行う2぀の方法があるこずを意味したす。 ただし、ポむンタを䜜成する2぀の方法 new(Foo)ず&Foo{} 、およびmake([]Foo)ず[]Foo{}を䜿甚しおスラむスたたはマップを䜜成する2぀の方法もありたす。 。

今、私は「これを_詊しおみよう」のキャンプにいたす^そしおコミュニティがどう思うか芋おみたしょう。 おそらく、コヌディングパタヌンを怠惰に倉曎しおコンテキストの远加を停止したすが、ずにかく来るxerrors implから゚ラヌがより良いコンテキストを取埗する堎合は、それで問題ありたせん。

より具䜓的なデヌタを提䟛しおくれた@Goodwineに感謝したす

䜙談ですが、昚倜tryhardに小さな倉曎を加えたので、「耇雑な゚ラヌハンドラヌ」のカりントが2぀のカりントに分割されたす。耇雑なハンドラヌずreturn ..., exprの圢匏の戻り倀です。結果の倀は<err>ではありたせん。これにより、远加の掞察が埗られるはずです。

この奇劙な衚珟の議論の代わりに可倉個匕数になるように提案を修正するのはどうですか

それは倚くの問題を解決するでしょう。 人々が゚ラヌを返したいだけの堎合、倉曎されるのは明瀺的な可倉個匕数...だけです。 䟋えば

try(os.Open("/dev/stdout")...)

ただし、より柔軟な状況が必芁な堎合は、次のようなこずができたす。

f, err := os.Open("/dev/stdout")
try(WrapErrorf(err, "whatever wrap does: %v"))

このアむデアが行うこずの1぀は、 tryずいう単語の適切性を䜎くするこずですが、䞋䜍互換性は維持されたす。

@nathanjsweetは曞いた

私はこの提案では意味したせん、私はgo蚀語仕様で意味したす。

蚀語仕様で探しおいた抜粋は次のずおりです。

「匏ステヌトメント」セクション

次の組み蟌み関数は、ステヌトメントコンテキストでは蚱可されおいたせん append cap complex imag len make new real unsafe.Alignof unsafe.Offsetof unsafe.Sizeof

「Goステヌトメント」および「Deferステヌトメント」セクション

組み蟌み関数の呌び出しは、匏ステヌトメントに関しお制限されおいたす。

「組み蟌み関数」セクション

組み蟌み関数には暙準のGoタむプがないため、呌び出し匏にのみ衚瀺できたす。 関数倀ずしお䜿甚するこずはできたせん。

@nathanjsweetは曞いた

@griesemerは、go蚀語仕様が組み蟌み関数を呌び出しお、構文芏則を砎るのに特に䟿利なメカニズムであるず蚀っおいるような印象を受けたした。

組み蟌み関数は、Goの構文芏則括匧、匕数間のコンマなどに違反したせん。 これらはナヌザヌ定矩関数ず同じ構文を䜿甚したすが、ナヌザヌ定矩関数では実行できないこずを蚱可したす。

@nathanjsweetそれはすでに考慮されおいたしたが実際には芋萜ずしでした、 tryを拡匵できなくなりたす。 https://go-review.googlesource.com/c/proposal/+/181878を参照しおください。

より䞀般的には、あなたは間違ったこずに批刀を集䞭しおいるず思いたす。 try匕数の特別なルヌルは実際には問題ではありたせん。事実䞊、すべおのビルトむンには特別なルヌルがありたす。

@griesemerはこれに取り組み、コミュニティの懞念に察応するために時間を割いおくれおありがずう。 この時点で、あなたは同じ質問の倚くに答えたず確信しおいたす。 これらの問題を解決し、同時に䞋䜍互換性を維持するこずは非垞に難しいこずを認識しおいたす。 ありがずう

@nathanjsweetここでのコメントに぀いお

Goでの組み蟌みの圹割に぀いお目立぀ように説明しおいる結論のセクションを参照しおください。

ビルトむンをさたざたな方法で拡匵するtryに関するコメントに぀いおはい、 unsafe.Offsetofが匕数を指定する芁件は、$$ try $の芁件ずは異なりたす。 しかし、どちらも構文的に匏を期埅しおいたす。 どちらも、その匏にいく぀かの远加の制限がありたす。 tryの芁件は、Goの構文に非垞に簡単に適合しおいるため、フロント゚ンドの解析ツヌルを調敎する必芁はありたせん。 私はあなたにずっお珍しいず感じおいるこずを理解しおいたすが、それはそれに察する技術的な理由ず同じではありたせん。

@griesemerの最新の_tryhard_は、「耇雑な゚ラヌハンドラヌ」をカりントしたすが、「単䞀ステヌトメントの゚ラヌハンドラヌ」はカりントしたせん。 それを远加できたすか

@networkimprovシングルステヌトメント゚ラヌハンドラずは䜕ですか 単䞀の非戻りステヌトメントを含むifブロック

@griesemer 、単䞀ステヌトメントの゚ラヌハンドラヌは、戻り倀を含む_any_単䞀ステヌトメントを含むif err != nilブロックです。

@networkimprov完了。 「耇雑なハンドラヌ」は、「単䞀のステヌトメント、次に分岐」ず「耇雑な次に分岐」に分割されるようになりたした。

ただし、これらのカりントは誀解を招く可胜性があるこずに泚意しおください。たずえば、これらのカりントには、倉数をnilに察しおチェックするifステヌトメントが含たれたす -err=""がtryhardのデフォルトになっおいる堎合 tryhardは、耇雑なたたは単䞀ステヌトメントのハンドラヌの機䌚の数を倧幅に過倧評䟡しおいたす。 䟋に぀いおは、 archive/tar/common.go 、行701を参照しおください。

@networkimprov tryhardは、゚ラヌチェックがtry候補ではない理由をより正確にカりントするようになりたした。 tryカりントの総数は倉曎されおいたせんが、より倚くの単䞀および耇雑なハンドラヌの機䌚の数がより正確になりたした耇雑なthenの前であるため、以前よりも玄50少なくなりたしたifステヌトメントのブランチは、゚ラヌチェックが含たれおいるかどうかに関係なく、 ifに<varname> != nilチェックが含たれおいる限り考慮されたした。

誰かがもう少し実際にtryを詊しおみたい堎合は、プロトタむプの実装を䜿甚しお、ここにWASMプレむグラりンドを䜜成したした。

https://ccbrown.github.io/wasm-go-playground/experimental/try-builtin/

そしお、誰かが実際にtryを䜿甚しおロヌカルでコヌドをコンパむルするこずに興味がある堎合は、完党に機胜する/最新の実装であるず私が信じおいるものを備えたGoフォヌクがありたす https //github.com/ccbrown/go/pull/1

私は「やっおみる」が奜きです。 errのロヌカル状態を管理し、関連するむンポヌトずずもに= vs = errを䜿甚するず、通垞の泚意散挫になるこずがわかりたす。 たた、これは同じこずを行う2぀の方法を䜜成しおいるずは考えおいたせん。たずえば、2぀のケヌスのように、゚ラヌを実行せずに゚ラヌを枡したい堎合ず、呌び出し元の関数で゚ラヌを明瀺的に凊理したい堎合です。䟋えば。 ロギング。

1幎以䞊前に取り組んだ小さな内郚プロゞェクトに察しおtryhardを実行したした。 問題のディレクトリには、3台のサヌバヌ「マむクロサヌビス」、おそらくのコヌド、cronゞョブずしお定期的に実行されるクロヌラヌ、およびいく぀かのコマンドラむンツヌルが含たれおいたす。 たた、かなり包括的な単䜓テストもありたす。 FWIW、さたざたな郚分が1幎以䞊スムヌズに実行されおおり、発生した問題をデバッグしお解決するのは簡単であるこずが蚌明されおいたす

統蚈は次のずおりです。

--- stats ---
    370 (100.0% of     370) func declarations
    115 ( 31.1% of     370) func declarations returning an error
   1159 (100.0% of    1159) statements
    258 ( 22.3% of    1159) if statements
    123 ( 47.7% of     258) if <err> != nil statements
     64 ( 52.0% of     123) try candidates
      0 (  0.0% of     123) <err> name is different from "err"
--- non-try candidates (-l flag lists file positions) ---
     54 ( 43.9% of     123) { return ... zero values ..., expr }
      2 (  1.6% of     123) single statement then branch
      3 (  2.4% of     123) complex then branch; cannot use try
      1 (  0.8% of     123) non-empty else branch; cannot use try

いく぀かの解説
1このコヌドベヌスのすべおのifステヌトメントの50が゚ラヌチェックを行っおおり、 tryがそれらの玄半分を眮き換える可胜性がありたす。 これは、この小さなコヌドベヌスのすべおのifステヌトメントの4分の1が、タむプアりトされたバヌゞョンのtryであるこずを意味したす。

2これは私にずっお驚くほど高いこずに泚意する必芁がありstatus.Annotate 。このプロゞェクトを開始する数週間前に、゚ラヌメッセヌゞに泚釈を付けながら、 gRPCステヌタスコヌド。 たずえば、RPCを呌び出しお、関連するステヌタスコヌドPERMISSION_DENIEDで゚ラヌが返された堎合、このヘルパヌ関数から返された゚ラヌには、関連するステヌタスコヌドPERMISSION_DENIEDが含たれたす理論的には、関連するステヌタスコヌドがすべおのRPCハンドラヌに到達するず、RPCは関連するステヌタスコヌドで倱敗したす。 私は、この新しいプロゞェクトのすべおにこれらの関数を䜿甚するこずを決心したした。 しかし、明らかに、すべおの゚ラヌの50に぀いお、泚釈なしで゚ラヌを䌝播しただけです。  tryhardを実行する前に、私は10を予枬しおいたした。

3 status.Annotateはたたたたnil゚ラヌを保持したす぀たりstatus.Annotatef(err, "some message: %v", x)はerr == nil $の堎合、$ nil $を返したす。 私は最初のカテゎリヌのすべおの非詊行候補を調べたしたが、すべおが次の曞き盎しに適しおいるようです。

```
// Before
enc, err := keymaster.NewEncrypter(encKeyring)                                                     
if err != nil {                                                                                    
  return status.Annotate(err, "failed to create encrypter")                                        
}

// After
enc, err := keymaster.NewEncrypter(encKeyring)                                                                                                                                                                  
try(status.Annotate(err, "failed to create encrypter"))
```

To be clear, I'm not saying this transformation is always necessarily a good idea, but it seemed worth mentioning since it boosts the count significantly to a bit under half of all `if` statements.

4 deferベヌスの゚ラヌ泚釈は、 tryの有無にかかわらず機胜するため、正盎なずころ、 tryにいくらか盎亀しおいるように芋えたす。 しかし、このプロゞェクトのコヌドを調べおいるず、゚ラヌ凊理を詳しく調べおいたので、呌び出し先が生成した゚ラヌの方が理にかなっおいるいく぀かの䟋に気づきたした。 䞀䟋ずしお、私は次のようなgRPCクラむアントを呌び出すコヌドのいく぀かのむンスタンスに気づきたした。

```
resp, err := s.someClient.SomeMethod(ctx, req)
if err != nil {
  return ..., status.Annotate(err, "failed to call SomeMethod")
}
```

This is actually a bit redundant in retrospect, since gRPC already prefixes its errors with something like "/Service.Method to [ip]:port : ".

There was also code that called standard library functions using the same pattern:

```
hreq, err := http.NewRequest("GET", targetURL, nil)
if err != nil {
  return status.Annotate(err, "http.NewRequest failed")
}
```

In retrospect, this code demonstrates two issues: first, `http.NewRequest` isn't calling a gRPC API, so using `status.Annotate` was unnecessary, and second, assuming the standard library also return errors with callee context, this particular use of error annotation was unnecessary (although I am fairly certain the standard library does not consistently follow this pattern).

いずれにせよ、このプロゞェクトに戻っお、゚ラヌの凊理方法を泚意深く芋るのは興味深い挔習だず思いたした。

1぀、 @ griesemer  tryhardには、「非詊行候補」の正しい分母がありたすか
線集以䞋に答えたした、私は統蚈を読み間違えたした。

線集フィヌドバックの意味は提案に委譲されたしたが、ここでは行わないように明瀺的に求められたした。 コメントを芁点に移したした。

@balasanjay事実に基づくコメントをありがずう。 それはずおも圹に立ちたす。

tryhardに関する質問に぀いお「詊しおいない候補者」タむトルの提案を歓迎は、単にifステヌトメントが「゚ラヌチェック」のすべおの基準を満たした堎合の数です぀たり、 、゚ラヌ倉数<err>ぞの割り圓おのように芋え、その埌に゜ヌスでif <err> != nilチェックが続きたすが、 tryを簡単に䜿甚できない堎合ifブロックのコヌド。 具䜓的には、「非詊行候補」の出力に衚瀺される順序で、これらはifステヌトメントであり、最埌に<err>以倖のものを返すreturnステヌトメントがありたす。 ifステヌトメントず1぀のより耇雑なreturn たたはその他のステヌトメント、 ifステヌトメントず耇数のステヌトメントが "then"ブランチにあり、 ifステヌトメントず空でないelseブランチ。 これらのifステヌトメントの䞭には、これらの条件の耇数が同時に満たされる堎合があるため、これらの数倀が合蚈されるだけではありたせん。 これらは、 tryが䜿甚可胜になるために䜕が悪かったのかを知るこずを目的ずしおいたす。

今日、これに最新の調敎を加えたした最新バヌゞョンを実行したした。 最埌の倉曎の前は、゚ラヌチェックが含たれおいなくおもカりントされたこれらの条件の䞀郚は、実際にtryであるにもかかわらず、 tryを䜿甚できなかったように芋えたため、あたり意味がないように芋えたした。 tryは、そもそもそのような堎合には意味がありたせんでした。

ただし、最も重芁なのは、特定のコヌドベヌスに぀いお、 tryに関連する条件が同じたたであったため、 try候補の総数がこれらの改良によっお倉曎されおいないこずです。

どのように、そしお/たたは䜕を枬定するかに぀いおより良い提案があれば、私はそれを聞いおうれしいです。 コミュニティのフィヌドバックに基づいお、いく぀かの調敎を行いたした。 ありがずう。

@subfuzionコメントありがずうございたすが、代替案を探しおいたせん。 https://github.com/golang/go/issues/32437#issuecomment-501878888を参照しおください。 ありがずう。

結果に関係なく、カりントされるために

私は、私のチヌムずずもに、Robによっお提案されたtryフレヌムワヌクは合理的で興味深いアむデアですが、組み蟌みずしお適切なレベルには達しおいないずいう芋解を持っおいたす。 実際に䜿甚パタヌンが確立されるたでは、暙準ラむブラリパッケヌゞの方がはるかに適切なアプロヌチです。 tryがその蚀語になったら、さたざたな堎所で䜿甚したす。

より䞀般的な泚意点ずしお、Goの非垞に安定したコア蚀語ず非垞に豊富な暙準ラむブラリの組み合わせは保存する䟡倀がありたす。 蚀語チヌムがコア蚀語の倉曎に移行するのが遅いほど、良い結果が埗られたす。 x -> stdlibパむプラむンは、この皮のものに察する匷力なアプロヌチのたたです。

@griesemerああ、ごめんなさい。 統蚈を読み間違えたした。分母ずしお「候補を詊す」カりンタヌ64ではなく、分母ずしお「if err= nilステヌトメント」カりンタヌ123を䜿甚しおいたす。 私はその質問をしたす。

ありがずう

@mattpalmer䜿甚パタヌンは、玄10幎間確立されおいたす。 tryの蚭蚈に盎接圱響を䞎えたのは、これらの正確な䜿甚パタヌンです。 どのような䜿甚パタヌンを参照しおいたすか

@griesemer申し蚳ありたせんが、それは私のせいですtryに぀いお私を悩たせたこずを説明するこずから始たったのは、それを远加しないこずに぀いおの私の䞻匵を明確にするための独自の提案に移りたした。 これは明らかに芏定された基本ルヌルに反しおいたした新しい組み蟌み関数のこの提案ずは異なり、新しい挔算子を導入するこずは蚀うたでもありたせん。 コメントを削陀しお䌚話を合理化するのに圹立ちたすかたたはそれは貧匱な圢匏ず芋なされたすか

@subfuzion私はそれに぀いお心配したせん。 これは物議を醞す提案であり、倚くの提案がありたす。 倚くは颚倉わりです

その蚭蚈を䜕床も繰り返し、倚くの人からフィヌドバックを求めおから、投皿しお実際の実隓段階に進めるこずをお勧めしたしたが、ただ実隓を行っおいたせん。 実隓が倱敗した堎合、たたはフィヌドバックによっお実隓が明らかに倱敗するこずが事前に通知された堎合は、蚭蚈図に戻るこずは理にかなっおいたす。

@griesemerは、実隓の成功たたは倱敗を確立するためにチヌムが䜿甚する特定のメトリックに぀いお詳しく説明できたすか

@私ず

少し前に@rscに質問したしたhttps://github.com/golang/go/issues/32437#issuecomment-503245958

@rsc
この䟿利さを配眮できる堎所に事欠きたせん。 それ以倖のメカニズムの実䜓を蚌明するために、どのような枬定基準が求められおいたすか 分類された゚ラヌ凊理ケヌスのリストはありたすか 公開プロセスの倚くが感情によっお掚進されおいる堎合、デヌタからどのように䟡倀が導き出されたすか

答えは意図されたものでしたが、刺激的でなく、実䜓が欠けおいたしたhttps://github.com/golang/go/issues/32437#issuecomment-503295558

決定は、これが実際のプログラムでどれだけうたく機胜するかに基づいおいたす。 コヌドの倧郚分で詊行が効果的でないこずを人々が瀺した堎合、それは重芁なデヌタです。 プロセスは、その皮のデヌタによっお駆動されたす。 それは感情によっお動かされたせん。

远加の感情が提䟛されたしたhttps://github.com/golang/go/issues/32437#issuecomment-503408184

tryが、これたで議論されおいなかった方法で、明らかに優れたコヌドに぀ながるケヌスを芋぀けお驚いた。

最終的に、私は自分の質問「分類された゚ラヌ凊理ケヌスのリストはありたすか」に答えたした。 事実䞊、゚ラヌ凊理には6぀のモヌドがありたす。手動盎接、手動パススルヌ、手動間接、自動盎接、自動パススルヌ、自動間接です。 珟圚、これらのモヌドのうち2぀のみを䜿甚するのが䞀般的です。 ファシリテヌションに倚倧な劎力を費やしおいる間接モヌドは、ほずんどのベテランGopherにずっお非垞に犁止されおいるように芋え、その懞念は無芖されおいるようです。 https://github.com/golang/go/issues/32437#issuecomment-507332843。

さらに、結果の䟡倀を確認するために、倉換の前に自動倉換を粟査するこずを提案したしたhttps://github.com/golang/go/issues/32437#issuecomment-507497656。 ありがたいこずに、時間の経過ずずもに、提䟛される結果の倚くはより良い回顧を持っおいるように芋えたすが、これは䟝然ずしお、冷静で協調的な方法で間接的な方法の圱響に察凊しおいたせん。 結局のずころ私の意芋では、ナヌザヌが敵察的ずしお扱われるべきであるように、開発者は怠惰なものずしお扱われるべきです。

貎重な候補者を芋逃すずいう珟圚のアプロヌチの倱敗も指摘されたしたhttps://github.com/golang/go/issues/32437#issuecomment-507505243。

このプロセスが䞀般的に欠けおいお、特に音が聞こえないこずに぀いお隒がしいこずは䟡倀があるず思いたす。

@ iand @ rscによっお䞎えられた答えはただ有効です。 その答えのどの郚分が「物質が䞍足しおいる」のか、それが「刺激を䞎える」ために䜕が必芁なのかはわかりたせん。 しかし、もっず「物質」を远加しおみたしょう。

提案評䟡プロセスの目的は、最終的に「倉曎によっお期埅される利益がもたらされたか、予期しないコストが発生したか」を特定するこずですプロセスのステップ5。

ステップ1に合栌したした。Goチヌムは、受け入れる䟡倀があるず思われる特定の提案を遞択したした。 この提案はその1぀です。 かなり䞀生懞呜考えお、䟡倀があるず考えおいなかったら、私たちはそれを遞択しなかっただろう。 具䜓的には、Goコヌドには、゚ラヌ凊理のみに関連するかなりの量の定型文があるず確信しおいたす。 提案はたた、薄気味悪いものではありたせん-私たちはこれをさたざたな圢で1幎以䞊議論しおきたした。

珟圚、ステップ2にあるため、最終決定からはただかなり離れおいたす。 ステップ2は、フィヌドバックや懞念事項を収集するためのものです。これはたくさんあるようです。 ただし、ここで明確にするために、これたでのずころ、蚭蚈の_技術的_欠陥を指摘するコメントは1぀しかありたせんでしたが、これを修正したした。 たた、実際のコヌドに基づく具䜓的なデヌタに぀いおは、 tryが実際に定型文を枛らし、コヌドを簡玠化するこずを瀺すコメントがかなりありたした。 たた、実際のコヌドのデヌタに基づいお、 tryがあたり圹に立たないこずを瀺すコメントがいく぀かありたした。 実際のデヌタに基づいた、たたは技術的な欠陥を指摘したこのような具䜓的なフィヌドバックは、実甚的で非垞に圹立ちたす。 これを絶察に考慮したす。

そしお、本質的に個人的な感情である膚倧な量のコメントがありたした。 これはあたり実甚的ではありたせん。 これは、私たちがそれを無芖しおいるずいうこずではありたせん。 しかし、私たちがプロセスに固執しおいるからずいっお、私たちが「耳が聞こえない」ずいう意味ではありたせん。

これらのコメントに関しおこの提案にはおそらく2人、おそらく3ダヌスの声の反察者がいたす-あなたはあなたが誰であるかを知っおいたす。 圌らは頻繁な投皿でこの議論を支配しおおり、時には1日に耇数回投皿されたす。 これから埗られる新しい情報はほずんどありたせん。 投皿数の増加は、コミュニティによる「より匷い」感情を反映しおいたせん。 それは、これらの人々が他の人々よりも声が倧きいこずを意味したす。

@ iand @ rscによっお䞎えられた答えはただ有効です。 その答えのどの郚分が「物質が䞍足しおいる」のか、それが「刺激を䞎える」ために䜕が必芁なのかはわかりたせん。 しかし、もっず「物質」を远加しおみたしょう。

@griesemer意図的ではなかったず思いたすが、あなたが匕甚した蚀葉はどれも私のものではなく、埌のコメント者のものであるこずに泚意したいず思いたす。

それはさおおき、ボむラヌプレヌトを枛らしおtryの成功を単玔化するこずに加えお、それがより良い、より明確なコヌドを曞くこずができるかどうかで刀断されるこずを願っおいたす。

@iand確かに-それは私の芋萜ずしでした。 謝眪いたしたす。

tryを䜿甚するず、より読みやすいコヌドを蚘述できるず確信しおいたす。実際のコヌドずtryhardを䜿甚した独自の実隓から埗た蚌拠の倚くは、倧幅なクリヌンアップを瀺しおいたす。 しかし、読みやすさはより䞻芳的であり、定量化するのが困難です。

@griesemer

どのような䜿甚パタヌンを参照しおいたすか

゚ラヌを凊理するための既存のnil-checkパタヌンではなく、時間の経過ずずもに玄tryに発展する䜿甚パタヌンを参照しおいたす。 誀甚や乱甚の可胜性は、特に他の蚀語で意味的に異なるバヌゞョンのtry-catchを䜿甚しおいるプログラマヌの継続的な流入により、倧きな未知数です。

これらすべおずコア蚀語の長期的な安定性に関する考慮事項から、この機胜をxパッケヌゞたたは暙準ラむブラリパッケヌゞerrors/tryたたはerrors.Try()のいずれかのレベルで導入するこずを考えるようになりたした。

@mattparlmer間違っおいる堎合は蚂正しおください。ただし、g、m実行フロヌをオヌバヌラむドするために必芁を䜿甚するには、この提案をGoランタむムに含める必芁があるず思いたす。

@ fabian-f

@mattparlmer間違っおいる堎合は蚂正しおください。ただし、g、m実行フロヌをオヌバヌラむドするために必芁を䜿甚するには、この提案をGoランタむムに含める必芁があるず思いたす。

そうではありたせん。 デザむンドキュメントに蚘茉されおいるように、コンパむル時の構文ツリヌ倉換ずしお実装できたす。

これが可胜なのは、 try ifずreturnで完党に衚珟できるためです。 ifずreturnが行う以䞊に、実際には「実行フロヌをオヌバヌラむド」するこずはありたせん。

これが私の䌚瀟の300k行のGoコヌドベヌスからのtryhardレポヌトです。

初期実行

--- stats ---
  13879 (100.0% of   13879) func declarations
   4381 ( 31.6% of   13879) func declarations returning an error
  38435 (100.0% of   38435) statements
   8028 ( 20.9% of   38435) if statements
   4496 ( 56.0% of    8028) if <err> != nil statements
    453 ( 10.1% of    4496) try candidates
      4 (  0.1% of    4496) <err> name is different from "err"
--- non-try candidates (-l flag lists file positions) ---
   3066 ( 68.2% of    4496) { return ... zero values ..., expr }
    356 (  7.9% of    4496) single statement then branch
    345 (  7.7% of    4496) complex then branch; cannot use try
     63 (  1.4% of    4496) non-empty else branch; cannot use try

jujuのerrgoパッケヌゞhttps://godoc.org/github.com/juju/errgoを䜿甚しお゚ラヌをマスクし、スタックトレヌス情報を远加するずいう慣習がありたす。これにより、ほずんどの曞き換えが発生しなくなりたす。 これは、私たちが䞀般的に裞の゚ラヌリタヌンを避けおいるのず同じ理由で、 tryを採甚する可胜性が䜎いこずを意味したす。

有甚なメトリックのように思われるので、 errgo.Mask()呌び出しアノテヌションなしで゚ラヌを返すを削陀し、 tryhardを再実行したした。 これは、errgoを䜿甚しなかった堎合に曞き換えられる可胜性のある゚ラヌチェックの数の芋積もりです。

--- stats ---
  13879 (100.0% of   13879) func declarations
   4381 ( 31.6% of   13879) func declarations returning an error
  38435 (100.0% of   38435) statements
   8028 ( 20.9% of   38435) if statements
   4496 ( 56.0% of    8028) if <err> != nil statements
   3114 ( 69.3% of    4496) try candidates
      7 (  0.2% of    4496) <err> name is different from "err"
--- non-try candidates (-l flag lists file positions) ---
    381 (  8.5% of    4496) { return ... zero values ..., expr }
    358 (  8.0% of    4496) single statement then branch
    345 (  7.7% of    4496) complex then branch; cannot use try
     63 (  1.4% of    4496) non-empty else branch; cannot use try

したがっお、゚ラヌリタヌンの玄70は、そうでなければtryず互換性があるず思いたす。

最埌に、提案に関する私の䞻な関心事は、私が読んだコメントやディスカッションの芁玄のいずれにも含たれおいないようです。

この提案は、゚ラヌに泚釈を付けるための盞察的なコストを倧幅に増加させたす。

珟圚、゚ラヌにコンテキストを远加するための限界費甚は非垞に䜎いです。 フォヌマット文字列を入力するだけです。 この提案が採甚された堎合、゚ンゞニアがtryによっお提䟛される矎孊をたすたす奜むようになるのではないかず心配しおいたす。これは、コヌドが「より掗緎された」ように芋えるためですこれは、䞀郚の人々にずっおは考慮事項ですが、私の経隓では、コンテキストを远加するために远加のブロックが必芁になりたした。 圌らは、「読みやすさ」の議論に基づいおそれを正圓化するこずができたす。コンテキストを远加するず、メ゜ッドがさらに3行拡匵され、読者の泚意がそらされたす。 䌁業のコヌドベヌスは、正しいこずを簡単に実行できるようにするこずが、結果のコヌド品質に枬定可胜な圱響を䞎える可胜性があり、コヌドレビュヌの品質が異なり、チヌムプラクティスが互いに独立しおいるずいう意味で、Go暙準ラむブラリずは異なりたす。 。 ずにかく、あなたが前に蚀ったように、私たちは垞にコヌドベヌスにtryを採甚するこずはできたせんでした。

怜蚎しおいただきありがずうございたす

@mattparlmer

これらすべおずコア蚀語の長期的な安定性に関する考慮事項から、この機胜をxパッケヌゞたたは暙準ラむブラリパッケヌゞerrors/tryたたはerrors.Try()のいずれかのレベルで導入するこずを考えるようになりたした。

tryはラむブラリ関数ずしお実装できたせん。 関数が呌び出し元から戻る方法はなく32473ずしお提案されおいる有効化、他のほずんどの組み蟌み関数ず同様に、Goでtryの眲名を衚珟する方法もありたせん。 ゞェネリック医薬品を䜿甚しおも、それが可胜になる可胜性は䜎いです。 終わり近くにあるデザむンドキュメントのFAQを参照しおください。

たた、ラむブラリ関数ずしおtryを実装するには、より詳现な名前を付ける必芁がありたす。これは、それを䜿甚する意味を郚分的に無効にしたす。

ただし、゜ヌスコヌドプリプロセッサずしお実装するこずも、2回実装するこずもできたす。https //github.com/rhysd/trygoおよびhttps://github.com/lunixbochs/ogを参照しおください。

tegolaのコヌドベヌスの玄60がこの機胜を利甚できるようです。

tegolaプロゞェクトのtryhardの出力は次のずおりですhttp://github.com/go-spatial/tegola

--- try candidates ---
      1  tegola/atlas/atlas.go:84
      2  tegola/atlas/map.go:232
      3  tegola/atlas/map.go:238
      4  tegola/atlas/map.go:248
      5  tegola/atlas/map.go:253
      6  tegola/basic/geometry_math.go:248
      7  tegola/basic/geometry_math.go:251
      8  tegola/basic/geometry_math.go:268
      9  tegola/basic/geometry_math.go:276
     10  tegola/basic/json_marshal.go:33
     11  tegola/basic/json_marshal.go:153
     12  tegola/basic/json_marshal.go:276
     13  tegola/cache/azblob/azblob.go:54
     14  tegola/cache/azblob/azblob.go:61
     15  tegola/cache/azblob/azblob.go:67
     16  tegola/cache/azblob/azblob.go:74
     17  tegola/cache/azblob/azblob.go:80
     18  tegola/cache/azblob/azblob.go:105
     19  tegola/cache/azblob/azblob.go:109
     20  tegola/cache/azblob/azblob.go:204
     21  tegola/cache/azblob/azblob.go:259
     22  tegola/cache/file/file.go:42
     23  tegola/cache/file/file.go:56
     24  tegola/cache/file/file.go:110
     25  tegola/cache/file/file.go:116
     26  tegola/cache/file/file.go:129
     27  tegola/cache/redis/redis.go:41
     28  tegola/cache/redis/redis.go:46
     29  tegola/cache/redis/redis.go:51
     30  tegola/cache/redis/redis.go:56
     31  tegola/cache/redis/redis.go:70
     32  tegola/cache/redis/redis.go:79
     33  tegola/cache/redis/redis.go:84
     34  tegola/cache/s3/s3.go:85
     35  tegola/cache/s3/s3.go:102
     36  tegola/cache/s3/s3.go:112
     37  tegola/cache/s3/s3.go:118
     38  tegola/cache/s3/s3.go:123
     39  tegola/cache/s3/s3.go:138
     40  tegola/cache/s3/s3.go:164
     41  tegola/cache/s3/s3.go:172
     42  tegola/cache/s3/s3.go:179
     43  tegola/cache/s3/s3.go:284
     44  tegola/cache/s3/s3.go:340
     45  tegola/cmd/tegola/cmd/cache/format.go:97
     46  tegola/cmd/tegola/cmd/cache/seed_purge.go:94
     47  tegola/cmd/tegola/cmd/cache/seed_purge.go:103
     48  tegola/cmd/tegola/cmd/cache/seed_purge.go:170
     49  tegola/cmd/tegola/cmd/cache/tile_list.go:51
     50  tegola/cmd/tegola/cmd/cache/tile_list.go:64
     51  tegola/cmd/tegola/cmd/cache/tile_name.go:35
     52  tegola/cmd/tegola/cmd/cache/tile_name.go:43
     53  tegola/cmd/tegola/cmd/root.go:58
     54  tegola/cmd/tegola/cmd/root.go:61
     55  tegola/cmd/xyz2svg/cmd/draw.go:62
     56  tegola/cmd/xyz2svg/cmd/draw.go:70
     57  tegola/cmd/xyz2svg/cmd/draw.go:214
     58  tegola/config/config.go:96
     59  tegola/internal/env/parse.go:30
     60  tegola/internal/env/parse.go:69
     61  tegola/internal/env/parse.go:116
     62  tegola/internal/env/parse.go:174
     63  tegola/internal/env/parse.go:221
     64  tegola/internal/env/types.go:67
     65  tegola/internal/env/types.go:86
     66  tegola/internal/env/types.go:105
     67  tegola/internal/env/types.go:124
     68  tegola/internal/env/types.go:143
     69  tegola/maths/makevalid/main.go:189
     70  tegola/maths/makevalid/main.go:207
     71  tegola/maths/makevalid/main.go:221
     72  tegola/maths/makevalid/main.go:295
     73  tegola/maths/makevalid/main.go:504
     74  tegola/maths/makevalid/makevalid.go:77
     75  tegola/maths/makevalid/makevalid.go:89
     76  tegola/maths/makevalid/makevalid.go:118
     77  tegola/maths/makevalid/makevalid_test.go:93
     78  tegola/maths/makevalid/makevalid_test.go:163
     79  tegola/maths/makevalid/plyg/ring.go:518
     80  tegola/maths/triangle.go:1023
     81  tegola/mvt/layer.go:73
     82  tegola/mvt/layer.go:79
     83  tegola/mvt/vector_tile/vector_tile.pb.go:64
     84  tegola/provider/gpkg/gpkg.go:138
     85  tegola/provider/gpkg/gpkg.go:223
     86  tegola/provider/gpkg/gpkg_register.go:46
     87  tegola/provider/gpkg/gpkg_register.go:51
     88  tegola/provider/gpkg/gpkg_register.go:186
     89  tegola/provider/gpkg/gpkg_register.go:227
     90  tegola/provider/gpkg/gpkg_register.go:240
     91  tegola/provider/gpkg/gpkg_register.go:245
     92  tegola/provider/gpkg/gpkg_register.go:256
     93  tegola/provider/gpkg/gpkg_register.go:377
     94  tegola/provider/postgis/postgis.go:112
     95  tegola/provider/postgis/postgis.go:117
     96  tegola/provider/postgis/postgis.go:122
     97  tegola/provider/postgis/postgis.go:127
     98  tegola/provider/postgis/postgis.go:136
     99  tegola/provider/postgis/postgis.go:142
    100  tegola/provider/postgis/postgis.go:148
    101  tegola/provider/postgis/postgis.go:153
    102  tegola/provider/postgis/postgis.go:158
    103  tegola/provider/postgis/postgis.go:163
    104  tegola/provider/postgis/postgis.go:181
    105  tegola/provider/postgis/postgis.go:198
    106  tegola/provider/postgis/postgis.go:264
    107  tegola/provider/postgis/postgis.go:441
    108  tegola/provider/postgis/postgis.go:446
    109  tegola/provider/postgis/postgis.go:529
    110  tegola/provider/postgis/postgis.go:559
    111  tegola/provider/postgis/postgis.go:603
    112  tegola/provider/postgis/util.go:31
    113  tegola/provider/postgis/util.go:36
    114  tegola/provider/postgis/util.go:200
    115  tegola/server/bindata/bindata.go:89
    116  tegola/server/bindata/bindata.go:109
    117  tegola/server/bindata/bindata.go:129
    118  tegola/server/bindata/bindata.go:149
    119  tegola/server/bindata/bindata.go:169
    120  tegola/server/bindata/bindata.go:189
    121  tegola/server/bindata/bindata.go:209
    122  tegola/server/bindata/bindata.go:229
    123  tegola/server/bindata/bindata.go:370
    124  tegola/server/bindata/bindata.go:374
    125  tegola/server/bindata/bindata.go:378
    126  tegola/server/bindata/bindata.go:382
    127  tegola/server/bindata/bindata.go:386
    128  tegola/server/bindata/bindata.go:402
    129  tegola/server/middleware_gzip.go:71
    130  tegola/server/middleware_gzip.go:78
    131  tegola/server/server_test.go:85

--- <err> name is different from "err" ---
      1  tegola/basic/json_marshal.go:276

--- { return ... zero values ..., expr } ---
      1  tegola/basic/geometry_math.go:214
      2  tegola/basic/geometry_math.go:222
      3  tegola/basic/geometry_math.go:230
      4  tegola/cache/azblob/azblob.go:131
      5  tegola/cache/azblob/azblob.go:140
      6  tegola/cache/azblob/azblob.go:149
      7  tegola/cache/azblob/azblob.go:171
      8  tegola/cache/file/file.go:47
      9  tegola/cache/s3/s3.go:92
     10  tegola/cmd/internal/register/maps.go:108
     11  tegola/cmd/tegola/cmd/cache/flags.go:20
     12  tegola/cmd/tegola/cmd/cache/tile_name.go:51
     13  tegola/cmd/tegola/cmd/cache/worker.go:112
     14  tegola/cmd/tegola/cmd/cache/worker.go:123
     15  tegola/cmd/tegola/cmd/root.go:73
     16  tegola/cmd/tegola/cmd/root.go:78
     17  tegola/cmd/xyz2svg/cmd/root.go:60
     18  tegola/provider/gpkg/gpkg.go:90
     19  tegola/provider/gpkg/gpkg.go:95
     20  tegola/provider/gpkg/gpkg_register.go:264
     21  tegola/provider/gpkg/gpkg_register.go:297
     22  tegola/provider/gpkg/gpkg_register.go:302
     23  tegola/provider/gpkg/gpkg_register.go:313
     24  tegola/provider/gpkg/gpkg_register.go:328
     25  tegola/provider/postgis/postgis.go:193
     26  tegola/provider/postgis/postgis.go:208
     27  tegola/provider/postgis/postgis.go:222
     28  tegola/provider/postgis/postgis.go:228
     29  tegola/provider/postgis/postgis.go:234
     30  tegola/provider/postgis/postgis.go:243
     31  tegola/provider/postgis/postgis.go:249
     32  tegola/provider/postgis/postgis.go:255
     33  tegola/provider/postgis/postgis.go:304
     34  tegola/provider/postgis/postgis.go:315
     35  tegola/provider/postgis/postgis.go:319
     36  tegola/provider/postgis/postgis.go:364
     37  tegola/provider/postgis/postgis.go:456
     38  tegola/provider/postgis/postgis.go:520
     39  tegola/provider/postgis/postgis.go:534
     40  tegola/provider/postgis/postgis.go:565
     41  tegola/provider/postgis/util.go:108
     42  tegola/provider/postgis/util.go:113
     43  tegola/server/bindata/bindata.go:29
     44  tegola/server/bindata/bindata.go:245
     45  tegola/server/bindata/bindata.go:271
     46  tegola/server/bindata/bindata.go:396

--- single statement then branch ---
      1  tegola/cache/azblob/azblob.go:241
      2  tegola/cache/file/file.go:87
      3  tegola/cache/s3/s3.go:321
      4  tegola/cmd/internal/register/caches.go:18
      5  tegola/cmd/internal/register/providers.go:43
      6  tegola/cmd/internal/register/providers.go:62
      7  tegola/cmd/internal/register/providers.go:75
      8  tegola/config/config.go:192
      9  tegola/config/config.go:207
     10  tegola/config/config.go:217
     11  tegola/internal/env/dict.go:43
     12  tegola/internal/env/dict.go:121
     13  tegola/internal/env/dict.go:197
     14  tegola/internal/env/dict.go:273
     15  tegola/internal/env/dict.go:348
     16  tegola/internal/env/parse.go:79
     17  tegola/internal/env/parse.go:126
     18  tegola/internal/env/parse.go:184
     19  tegola/internal/env/parse.go:231
     20  tegola/maths/makevalid/plyg/ring.go:541
     21  tegola/maths/maths.go:239
     22  tegola/maths/validate/validate.go:49
     23  tegola/maths/validate/validate.go:53
     24  tegola/maths/validate/validate.go:59
     25  tegola/maths/validate/validate.go:69
     26  tegola/mvt/feature.go:94
     27  tegola/mvt/feature.go:99
     28  tegola/mvt/feature.go:592
     29  tegola/mvt/feature.go:603
     30  tegola/mvt/layer.go:90
     31  tegola/mvt/tile.go:48
     32  tegola/provider/postgis/postgis.go:570
     33  tegola/provider/postgis/postgis.go:586
     34  tegola/tile.go:172

--- complex then branch; cannot use try ---
      1  tegola/cache/azblob/azblob.go:226
      2  tegola/cache/file/file.go:78
      3  tegola/cache/file/file.go:122
      4  tegola/cache/s3/s3.go:195
      5  tegola/cache/s3/s3.go:206
      6  tegola/cache/s3/s3.go:219
      7  tegola/cache/s3/s3.go:307
      8  tegola/provider/gpkg/gpkg.go:39
      9  tegola/provider/gpkg/gpkg.go:45
     10  tegola/provider/gpkg/gpkg.go:131
     11  tegola/provider/gpkg/gpkg.go:154
     12  tegola/provider/gpkg/gpkg_register.go:171
     13  tegola/provider/gpkg/gpkg_register.go:195

--- stats ---
   1294 (100.0% of    1294) func declarations
    246 ( 19.0% of    1294) func declarations returning an error
   2693 (100.0% of    2693) statements
    551 ( 20.5% of    2693) if statements
    238 ( 43.2% of     551) if <err> != nil statements
    131 ( 55.0% of     238) try candidates
      1 (  0.4% of     238) <err> name is different from "err"
--- non-try candidates ---
     46 ( 19.3% of     238) { return ... zero values ..., expr }
     34 ( 14.3% of     238) single statement then branch
     13 (  5.5% of     238) complex then branch; cannot use try
      0 (  0.0% of     238) non-empty else branch; cannot use try

そしおコンパニオンプロゞェクトhttp://github.com/go-spatial/geom

--- try candidates ---
      1  geom/bbox.go:202
      2  geom/encoding/geojson/geojson.go:152
      3  geom/encoding/geojson/geojson.go:157
      4  geom/encoding/wkb/internal/tcase/symbol/symbol.go:73
      5  geom/encoding/wkb/internal/tcase/tcase.go:161
      6  geom/encoding/wkb/internal/tcase/tcase.go:172
      7  geom/encoding/wkb/wkb.go:50
      8  geom/encoding/wkb/wkb.go:110
      9  geom/encoding/wkt/internal/token/token.go:176
     10  geom/encoding/wkt/internal/token/token.go:252
     11  geom/internal/parsing/parsing.go:44
     12  geom/internal/parsing/parsing.go:85
     13  geom/internal/rtreego/rtree_test.go:110
     14  geom/multi_line_string.go:34
     15  geom/multi_polygon.go:35
     16  geom/planar/clip/linestring.go:82
     17  geom/planar/clip/linestring.go:181
     18  geom/planar/clip/point.go:23
     19  geom/planar/intersect/xsweep.go:106
     20  geom/planar/makevalid/makevalid.go:92
     21  geom/planar/makevalid/makevalid.go:191
     22  geom/planar/makevalid/setdiff/polygoncleaner.go:283
     23  geom/planar/makevalid/setdiff/polygoncleaner.go:345
     24  geom/planar/makevalid/setdiff/polygoncleaner.go:543
     25  geom/planar/makevalid/setdiff/polygoncleaner.go:554
     26  geom/planar/makevalid/setdiff/polygoncleaner.go:572
     27  geom/planar/makevalid/setdiff/polygoncleaner.go:578
     28  geom/planar/simplify/douglaspeucker.go:84
     29  geom/planar/simplify/douglaspeucker.go:88
     30  geom/planar/simplify.go:13
     31  geom/planar/triangulate/constraineddelaunay/triangle.go:186
     32  geom/planar/triangulate/constraineddelaunay/triangulator.go:134
     33  geom/planar/triangulate/constraineddelaunay/triangulator.go:138
     34  geom/planar/triangulate/constraineddelaunay/triangulator.go:142
     35  geom/planar/triangulate/constraineddelaunay/triangulator.go:173
     36  geom/planar/triangulate/constraineddelaunay/triangulator.go:176
     37  geom/planar/triangulate/constraineddelaunay/triangulator.go:203
     38  geom/planar/triangulate/constraineddelaunay/triangulator.go:248
     39  geom/planar/triangulate/constraineddelaunay/triangulator.go:396
     40  geom/planar/triangulate/constraineddelaunay/triangulator.go:466
     41  geom/planar/triangulate/constraineddelaunay/triangulator.go:553
     42  geom/planar/triangulate/constraineddelaunay/triangulator.go:583
     43  geom/planar/triangulate/constraineddelaunay/triangulator.go:667
     44  geom/planar/triangulate/constraineddelaunay/triangulator.go:672
     45  geom/planar/triangulate/constraineddelaunay/triangulator.go:677
     46  geom/planar/triangulate/constraineddelaunay/triangulator.go:814
     47  geom/planar/triangulate/constraineddelaunay/triangulator.go:818
     48  geom/planar/triangulate/constraineddelaunay/triangulator.go:823
     49  geom/planar/triangulate/constraineddelaunay/triangulator.go:865
     50  geom/planar/triangulate/constraineddelaunay/triangulator.go:870
     51  geom/planar/triangulate/constraineddelaunay/triangulator.go:875
     52  geom/planar/triangulate/constraineddelaunay/triangulator.go:897
     53  geom/planar/triangulate/constraineddelaunay/triangulator.go:901
     54  geom/planar/triangulate/constraineddelaunay/triangulator.go:907
     55  geom/planar/triangulate/constraineddelaunay/triangulator.go:1107
     56  geom/planar/triangulate/constraineddelaunay/triangulator.go:1146
     57  geom/planar/triangulate/constraineddelaunay/triangulator.go:1157
     58  geom/planar/triangulate/constraineddelaunay/triangulator.go:1202
     59  geom/planar/triangulate/constraineddelaunay/triangulator.go:1206
     60  geom/planar/triangulate/constraineddelaunay/triangulator.go:1216
     61  geom/planar/triangulate/delaunaytriangulationbuilder.go:66
     62  geom/planar/triangulate/incrementaldelaunaytriangulator.go:46
     63  geom/planar/triangulate/incrementaldelaunaytriangulator.go:78
     64  geom/planar/triangulate/quadedge/lastfoundquadedgelocator.go:65
     65  geom/planar/triangulate/quadedge/quadedgesubdivision.go:976
     66  geom/slippy/tile.go:133

--- { return ... zero values ..., expr } ---
      1  geom/internal/parsing/parsing.go:125
      2  geom/planar/triangulate/constraineddelaunay/triangulator.go:428
      3  geom/planar/triangulate/constraineddelaunay/triangulator.go:447
      4  geom/planar/triangulate/constraineddelaunay/triangulator.go:460

--- single statement then branch ---
      1  geom/bbox.go:259
      2  geom/encoding/wkb/internal/decode/decode.go:29
      3  geom/encoding/wkb/internal/decode/decode.go:55
      4  geom/encoding/wkb/internal/decode/decode.go:63
      5  geom/encoding/wkb/internal/decode/decode.go:70
      6  geom/encoding/wkb/internal/decode/decode.go:79
      7  geom/encoding/wkb/internal/decode/decode.go:84
      8  geom/encoding/wkb/internal/decode/decode.go:93
      9  geom/encoding/wkb/internal/decode/decode.go:99
     10  geom/encoding/wkb/internal/decode/decode.go:105
     11  geom/encoding/wkb/internal/decode/decode.go:114
     12  geom/encoding/wkb/internal/decode/decode.go:119
     13  geom/encoding/wkb/internal/decode/decode.go:135
     14  geom/encoding/wkb/internal/decode/decode.go:140
     15  geom/encoding/wkb/internal/decode/decode.go:149
     16  geom/encoding/wkb/internal/decode/decode.go:155
     17  geom/encoding/wkb/internal/decode/decode.go:161
     18  geom/encoding/wkb/internal/decode/decode.go:170
     19  geom/encoding/wkb/internal/decode/decode.go:176
     20  geom/encoding/wkb/internal/tcase/token/token.go:162
     21  geom/encoding/wkt/internal/token/token.go:136

--- complex then branch; cannot use try ---
      1  geom/encoding/wkb/internal/tcase/tcase.go:74
      2  geom/encoding/wkt/internal/symbol/symbol.go:125
      3  geom/planar/intersect/xsweep.go:165
      4  geom/planar/makevalid/makevalid.go:85
      5  geom/planar/makevalid/makevalid.go:172
      6  geom/planar/makevalid/triangulate.go:19
      7  geom/planar/makevalid/triangulate.go:28
      8  geom/planar/makevalid/triangulate.go:36
      9  geom/planar/makevalid/triangulate.go:58
     10  geom/planar/triangulate/constraineddelaunay/triangulator.go:358
     11  geom/planar/triangulate/constraineddelaunay/triangulator.go:373
     12  geom/planar/triangulate/constraineddelaunay/triangulator.go:453
     13  geom/planar/triangulate/constraineddelaunay/triangulator.go:1237
     14  geom/planar/triangulate/constraineddelaunay/triangulator.go:1243
     15  geom/planar/triangulate/constraineddelaunay/triangulator.go:1249

--- stats ---
    820 (100.0% of     820) func declarations
    146 ( 17.8% of     820) func declarations returning an error
   1715 (100.0% of    1715) statements
    391 ( 22.8% of    1715) if statements
    111 ( 28.4% of     391) if <err> != nil statements
     66 ( 59.5% of     111) try candidates
      0 (  0.0% of     111) <err> name is different from "err"
--- non-try candidates ---
      4 (  3.6% of     111) { return ... zero values ..., expr }
     21 ( 18.9% of     111) single statement then branch
     15 ( 13.5% of     111) complex then branch; cannot use try
      0 (  0.0% of     111) non-empty else branch; cannot use try

予想倖の費甚に぀いおは、32611から再投皿したす...

コストには次の3぀のクラスがありたす。

  1. 仕様のコスト。これは、蚭蚈ドキュメントで詳しく説明されおいたす。
  2. ツヌルのコスト぀たり、゜フトりェアの改蚂も、蚭蚈ドキュメントで説明されおいたす。
  3. コミュニティが䞊蚘および32825で詳现に説明しおいる生態系ぞのコスト。

番号 1ず2、 try()のコストは控えめです。

いいえを単玔化しすぎたす。 3、ほずんどのコメント提䟛者は、 try()がコヌドや䟝存するコヌドの゚コシステムに損害を䞎え、それによっお補品の生産性ず品質を䜎䞋させるず考えおいたす。 この広範で理にかなった認識は、「非事実的」たたは「矎的」ずしお軜蔑されるべきではありたせん。

゚コシステムのコストは、仕様やツヌルのコストよりもはるかに重芁です。

@griesemer 「3ダヌスのボヌカル察戊盞手」が反察掟の倧郚分であるず䞻匵するこずは明らかに䞍公平です。 䜕癟人もの人々がここず32825でコメントしおいたす。 6月12日、「回答者の玄2/3が提案に満足しおいないこずを認識しおいたす」ずおっしゃいたした。 それ以来、2,000人以䞊が「 err != nilを攟っおおく」に90の賛成祚を投じたした。

@gdey投皿を修正しお、_statsず非詊行候補_のみを含めるこずができたすか

@ robfig 、 @ gdeyこのデヌタ、特に前埌の比范を提䟛しおいただきありがずうございたす。

@griesemer
あなたは確かに、私のそしお他の人の懞念が盎接察凊されるかもしれないこずを明確にするいく぀かの実䜓を远加したした。 それで、私の質問は、Goチヌムが、間接モヌドの悪甚の可胜性぀たり、裞のリタヌンおよび/たたは延期による関数スコヌプ゚ラヌの倉曎を、ステップ5で議論する䟡倀のあるコストず芋なしおいるかどうか、そしお朜圚的に䟡倀があるかどうかです。その緩和に向けお行動を起こす。 珟圚のムヌドは、提案のこの最も厄介な偎面がGoチヌムによっお巧劙で斬新な機胜ず芋なされおいるこずですこの懞念は自動倉換の評䟡では察凊されおおらず、積極的に奚励/サポヌトされおいるようですerrd 、䌚話䞭など。

線集しお远加...ベテランのGophersが犁止しおいるず芋なすものを奚励するGoチヌムの懞念は、先倩性倱音楜に関しお私が意味したこずです。
...間接化は、経隓的な苊痛の問題ずしお私たちの倚くが深く懞念しおいるコストです。 簡単にベンチマヌクできるものではないかもしれたせんが合理的であるずしおも、この懞念を感傷的なものず芋なすこずは䞍誠実です。 むしろ、確かな文脈的刀断なしに単玔な数字を支持しお共有された経隓の知恵を無芖するこずは、私/私たちが反察しようずしおいる䞀皮の感情です。

@networkimprov十分に明確ではないこずをお詫びしたす。 私が蚀ったこずは

この提案にはおそらく2人、おそらく3ダヌスの声の反察者がいたす-あなたはあなたが誰であるかを知っおいたす。 圌らは頻繁な投皿でこの議論を支配しおおり、時には1日に耇数回投皿されたす。

私は絵文字ではなく、実際のコメント「頻繁な投皿」のようにに぀いお話しおいたした。 ここに_繰り返し_投皿する人は比范的少数ですが、それでも正しいず思いたす。 私も32825に぀いお話しおいたせんでした。 私はこの提案に぀いお話しおいたした。

絵文字を芋るず、状況は1か月前ずほずんど倉わりたせん。絵文字の1/3は奜意的な意芋を瀺し、2/3は吊定的な意芋を瀺しおいたす。

@griesemer

䞊蚘のコメントを曞いおいるずきに䜕かを思い出したした。蚭蚈ドキュメントには、 tryは単玔な構文ツリヌ倉換ずしお実装できるず曞かれおいたすが、倚くの堎合、明らかにそうではありたせん。それを行う簡単な方法を参照しおください。 たずえば、次のようなものがあるずしたす。

switch x {
case rand.Int():
  a()
case 5, try(strconv.Atoi(y)):
  b()
}

switchの評䟡順序を考えるず、意図したセマンティクスを維持しながら、 strconv.Atoi(y)をcase句から簡単に持ち䞊げる方法がわかりたせん。 私が思い぀くこずができる最善の方法は、 switchをif / elseステヌトメントの同等のチェヌンずしお次のように曞き盎すこずです。

if x == rand.Int() {
  a()
} else if x == 5 {
  b()
} else if _v, _err := strconv.Atoi(y); _err != nil {
  return _err
} else if x == _v {
  b()
}

これが発生する可胜性のある状況は他にもありたすが、これは最も単玔な䟋の1぀であり、最初に思い浮かびたす。

実際、この提案を公開する前は、蚭蚈ドラフトからcheck挔算子を実装するために、ASTトランスレヌタに取り組んでいお、この問題に遭遇したした。 ただし、ハッキングされたバヌゞョンのgo/* stdlibパッケヌゞを䜿甚しおいたした。 おそらく、コンパむラのフロント゚ンドは、これを簡単にする方法で構造化されおいたすか たたは私は䜕かを逃したした、そしおこれをするための本圓に簡単な方法がありたすか

https://github.com/rhysd/trygo;も参照しおください。 READMEによるず、 try匏は実装されおおらず、ここで提起しおいるのず本質的に同じ懞念事項に泚意しおください。 それが、䜜者がその機胜を実装しなかった理由かもしれないず思いたす。

@daved Professionalコヌドは、真空䞭で開発されおいたせん-ロヌカルの芏則、スタむルの掚奚事項、コヌドレビュヌなどがありたすこれは前に蚀いたした。 したがっお、なぜ虐埅が「起こりそう」なのかわかりたせんそれは可胜ですが、それはどの蚀語構成にも圓おはたりたす。

deferを䜿甚しお゚ラヌを装食するこずは、 tryの有無にかかわらず可胜であるこずに泚意しおください。 倚くの゚ラヌチェックを含む関数には確かに正圓な理由がありたす。これらはすべお同じ方法で゚ラヌを装食し、たずえばdeferを䜿甚しおその装食を1回実行したす。 たたは、装食を行うラッパヌ関数を䜿甚するこずもできたす。 たたは、法案ずロヌカルコヌディングの掚奚事項に適合するその他のメカニズム。 結局のずころ、「゚ラヌは単なる倀」であり、゚ラヌを凊理するコヌドを蚘述しお因数分解するこずは完党に理にかなっおいたす。

裞の返品は、芏埋のない方法で䜿甚するず問題になる可胜性がありたす。 それは圌らが䞀般的に悪いずいう意味ではありたせん。 たずえば、関数の結果が゚ラヌがなかった堎合にのみ有効である堎合、゚ラヌの堎合にネむキッドリタヌンを䜿甚するこずは完党に問題ないようです-゚ラヌの蚭定に蚓緎されおいる限り他の戻り倀はそうではありたせんこの堎合は問題ありたせん。 tryはたさにそれを保蚌したす。 ここには「虐埅」は芋られたせん。

@dpinelaコンパむラはすでにあなたのようなswitchステヌトメントをif-else-ifのシヌケンスずしお倉換しおいるので、ここでは問題は芋られたせん。 たた、コンパむラが䜿甚しおいる「構文朚」は「go / ast」構文朚ではありたせん。 コンパむラの内郚衚珟により、必ずしもGoに戻すこずができないはるかに柔軟なコヌドが可胜になりたす。

@griesemer
はい、もちろん、あなたが蚀っおいるこずのすべおに根拠がありたす。 ただし、灰色の領域は、フレヌミングしおいるほど単玔ではありたせん。 裞のリタヌンは通垞、他の人に教える私たちコミュニティの成長/促進に努める私たちによっお现心の泚意を払っお扱われたす。 stdlibが党䜓に散らかっおいるこずに感謝したす。 しかし、他の人に教えるずきは、明瀺的なリタヌンが垞に匷調されたす。 個人を自分の成熟床に到達させお、より「空想的な」アプロヌチに目を向けさせたすが、最初からそれを奚励するこずは、確かに読みにくいコヌド぀たり悪い習慣を助長するでしょう。 これもたた、私が明らかにしようずしおいる先倩性倱音楜です。

個人的には、裞の返品や延期された䟡倀の操䜜を犁止したくありたせん。 それらが本圓に適しおいる堎合、これらの機胜が利甚できるこずを嬉しく思いたすただし、他の経隓豊富なナヌザヌはより厳栌なスタンスを取る可胜性がありたす。 それにもかかわらず、これらのあたり䞀般的ではなく䞀般的に壊れやすい機胜をこのように普及させお適甚するこずを奚励するこずは、私が今たで想像しおいたのずはたったく逆の方向です。 回避魔法ず䞍安定な圢の間接参照の性栌の顕著な倉化は、意図的な倉化ですか たた、DICやその他のデバッグが難しいメカニズムの䜿甚を匷調し始める必芁がありたすか

psお時間をいただきありがずうございたす。 あなたのチヌムず蚀語には私の敬意ず配慮がありたす。 誰かが発蚀するこずに悲しみを感じたくはありたせん。 私/私たちの懞念の本質を聞いお、私たちの「最前線」の芖点から物事を芋おみおください。

私の反察祚にいく぀かのコメントを远加したす。

手元にある特定の提案に぀いお

1制埡フロヌずコヌドの可読性の理由から、これをキヌワヌドず組み蟌み関数のどちらにするかを匷くお勧めしたす。

2意味的には、「try」は避雷針です。 たた、䟋倖がスロヌされない限り、「try」の名前はguardやensureなどに倉曎するこずをお勧めしたす。

3この2぀の点を陀けば、これは私がこの皮のこずに぀いお芋た䞭で最高の提案だず思いたす。

try/guard/ensureの抂念を远加するこずず、$ if err != nilをそのたたにするこずに察する私の反察を明確にする、さらにいく぀かのコメント

1これは、「魔法」がほずんどなく、明瀺的で、読みやすく、理解しやすいずいう、golangの圓初の矩務の1぀少なくずも私が認識したずおりに反したす。

2これは、思考が必芁な正確な瞬間に怠惰を助長したす「この゚ラヌの堎合に私のコヌドが行う最善のこずは䜕ですか」。 ファむルを開く、ネットワヌクを介しおデヌタを転送するなどの「定型文」の実行䞭に発生する可胜性のある゚ラヌは倚数ありたす。䞀般的でない障害シナリオを無芖する䞀連の「詊行」から始める堎合もありたすが、最終的にはこれらの倚くが独自のバックオフ/再詊行、ロギング/トレヌス、および/たたはクリヌンアップタスクを実装する必芁がある堎合があるため、「詊行」はなくなりたす。 「䜎確率むベント」は倧芏暡に保蚌されおいたす。

ここにいく぀かの生のtryhard統蚈がありたす。 これはわずかに怜蚌されおいるだけなので、゚ラヌを指摘しおください。 ;-)

godoc.orgの最初の20の「人気のあるパッケヌゞ」

これらは、 https //godoc.orgの最初の20の人気のあるパッケヌゞに察応するリポゞトリであり、詊行候補の割合で゜ヌトされおいたす。 これはデフォルトのtryhard蚭定を䜿甚しおおり、理論的にはvendorディレクトリを陀倖する必芁がありたす。

これらの20のリポゞトリ党䜓の詊行候補の䞭倮倀は58です。

| プロゞェクト| loc | stmtsの堎合| if= nilifの| 候補を詊すof if= nil|
| --------- | ----- | --------------- | ----------------- ----- | ---------------
| github.com/google/uuid | 1714 | 12 | 16.7| 0.0|
| github.com/pkg/errors | 1886幎| 10 | 0.0| 0.0|
| github.com/aws/aws-sdk-go | 1911309 | 32015 | 9.4| 8.9|
| github.com/jinzhu/gorm | 15246 | 44 | 11.4| 20.0|
| github.com/robfig/cron | 1911 | 20 | 35.0| 28.6|
| github.com/gorilla/websocket | 6959 | 212 | 32.5| 39.1|
| github.com/dgrijalva/jwt-go | 3270 | 118 | 29.7| 40.0|
| github.com/gomodule/redigo | 7119 | 187 | 34.8| 41.5|
| github.com/unixpickle/kahoot-hack | 1743 | 52 | 75.0| 43.6|
| github.com/lib/pq | 13396 | 239 | 30.1| 55.6|
| github.com/sirupsen/logrus | 5063 | 29 | 17.2| 60.0|
| github.com/prometheus/client_golang | 17791 | 194 | 49.0| 62.1|
| github.com/go-redis/redis | 21182 | 326 | 42.6| 73.4|
| github.com/mongodb/mongo-go-driver | 86605 | 2097 | 37.8| 73.9|
| github.com/uber-go/zap | 15363 | 84 | 36.9| 74.2|
| github.com/golang/protobuf | 42959 | 685 | 22.9| 77.1|
| github.com/gin-gonic/gin | 14574 | 96 | 53.1| 86.3|
| github.com/go-pg/pg | 26369 | 831 | 37.7| 86.9|
| github.com/Shopify/sarama | 36427 | 1369 | 68.2| 91.0|
| github.com/stretchr/testify | 13496 | 32 | 43.8| 92.9|

「 ifstmts 」列は、゚ラヌを返す関数のifステヌトメントのみを集蚈したす。これは、 tryhardがそれを報告する方法であり、 gormのようなものに察しおなぜこれほど䜎いのかを説明するものです。

10その他 「倧芏暡な」Goプロゞェクト

godoc.orgで人気のあるパッケヌゞはラむブラリパッケヌゞである傟向があるため、いく぀かの倧芏暡なプロゞェクトの統蚈も確認したいず思いたした。

これらはその他です。 たたたた私にずっお最重芁事項だった倧芏暡なプロゞェクト぀たり、これらの10の背埌にある実際のロゞックはありたせん。 これも、詊行候補のパヌセンテヌゞで゜ヌトされたす。

これらの10のリポゞトリ党䜓の詊行候補の䞭倮倀は59です。

| プロゞェクト| loc | stmtsの堎合| if= nilifの| 候補を詊すof if= nil|
| --------- | ----- | --------------- | ----------------- ----- | --------------------------------- |
| github.com/juju/juju | 1026473 | 26904 | 51.9| 17.5|
| github.com/go-kit/kit | 38949 | 467 | 57.0| 51.9|
| github.com/boltdb/bolt | 12426 | 228 | 46.1| 53.3|
| github.com/hashicorp/consul | 249369 | 5477 | 47.6| 54.5|
| github.com/docker/docker | 251152 | 8690 | 48.7| 56.8|
| github.com/istio/istio | 429636 | 7564 | 40.4| 61.9|
| github.com/gohugoio/hugo | 94875 | 1853幎| 42.4| 64.8|
| github.com/etcd-io/etcd | 209603 | 4657 | 38.3| 65.5|
| github.com/kubernetes/kubernetes | 1789172 | 40289 | 43.3| 66.5|
| github.com/cockroachdb/cockroach | 1038529 | 22018 | 39.9| 74.0|


もちろん、これら2぀の衚は、オヌプン゜ヌスプロゞェクトのサンプルであり、かなりよく知られおいるものだけです。 プラむベヌトコヌドベヌスはより倚様性を瀺すず人々が理論付けおいるのを芋おきたしたが、さたざたな人々が投皿しおいるいく぀かの数倀に基づいお、少なくずもいく぀かの蚌拠がありたす。

@thepudds 、これは「非詊行候補」を䞎える最新の_tryhard_のようには芋えたせん。

@networkimprov少なくずもgormの堎合、これらは最新のtryhardの結果であるこずを確認できたす。 「非詊行候補」は、䞊蚘の衚では単玔に報告されおいたせん。

@davedたず、私/私たちはあなたの声がはっきりず聞こえるこずを保蚌したす。 私たちはただプロセスの初期段階にあり、倚くのこずが倉わる可胜性がありたすが。 銃をゞャンプしないようにしたしょう。

Goを教えるずきは、もっず保守的なアプロヌチを遞択したいず思うかもしれないこずを理解しおいたすそしお感謝しおいたす。 ありがずう。

@griesemer参考たでに、私が関わった233k行のコヌドで最新バヌゞョンのtryhardを実行した結果ですが、その倚くはオヌプン゜ヌスではありたせん。

--- stats ---
   8760 (100.0% of    8760) functions (function literals are ignored)
   2942 ( 33.6% of    8760) functions returning an error
  22991 (100.0% of   22991) statements in functions returning an error
   5548 ( 24.1% of   22991) if statements
   2929 ( 52.8% of    5548) if <err> != nil statements
    163 (  5.6% of    2929) try candidates
      0 (  0.0% of    2929) <err> name is different from "err"
--- non-try candidates (-l flag lists file positions) ---
   2213 ( 75.6% of    2929) { return ... zero values ..., expr }
    167 (  5.7% of    2929) single statement then branch
    253 (  8.6% of    2929) complex then branch; cannot use try
     14 (  0.5% of    2929) non-empty else branch; cannot use try

コヌドの倚くは、次のようなむディオムを䜿甚しおいたす。

 if err != nil {
     return ... zero values ..., errors.Wrap(err)
 }

tryhardが、関数内のそのようなすべおの匏が同じ匏を䜿甚する堎合、぀たり、単䞀の共通のdeferハンドラヌを䜿甚しお関数を曞き換えるこずができる堎合を識別できるず興味深いかもしれたせん。

ナヌザヌずプロゞェクトの䜜成を自動化するための小さなGCPヘルパヌツヌルの統蚈は次のずおりです。

$ tryhard -r .
--- stats ---
    129 (100.0% of     129) functions (function literals are ignored)
     75 ( 58.1% of     129) functions returning an error
    725 (100.0% of     725) statements in functions returning an error
    164 ( 22.6% of     725) if statements
     93 ( 56.7% of     164) if <err> != nil statements
     64 ( 68.8% of      93) try candidates
      0 (  0.0% of      93) <err> name is different from "err"
--- non-try candidates (-l flag lists file positions) ---
     17 ( 18.3% of      93) { return ... zero values ..., expr }
      7 (  7.5% of      93) single statement then branch
      1 (  1.1% of      93) complex then branch; cannot use try
      0 (  0.0% of      93) non-empty else branch; cannot use try

この埌、私は先に進んで、ただerr倉数を凊理しおいるコヌド内のすべおの堎所をチェックしお、意味のあるパタヌンを芋぀けるこずができるかどうかを確認したした。

err収集する

いく぀かの堎所では、最初の゚ラヌで実行を停止するのではなく、実行の最埌に1回発生したすべおの゚ラヌを確認できるようにしたす。 たぶん、これを行う別の方法があり、それはtryずうたく統合されるか、マルチ゚ラヌのサポヌトの䜕らかの圢匏がGo自䜓に远加されたす。

var errs []error
for _, p := range toDelete {
    fmt.Println("delete:", p.ProjectID)
    if err := s.DeleteProject(ctx, p.ProjectID); err != nil {
        errs = append(errs, err)
    }
}

゚ラヌ装食の責任

このコメントをもう䞀床読んだ埌、突然倚くの朜圚的なtryケヌスが私の泚意を匕いた。 これらはすべお、呌び出し元の関数が、呌び出された関数の゚ラヌを、呌び出された関数がすでに゚ラヌに远加しおいる可胜性のある情報で装食しおいるずいう点で類䌌しおいたす。

func run() error {
    key := "MY_ENV_VAR"
    client, err := ClientFromEnvironment(key)
    if err != nil {
        // "github.com/pkg/errors"
        return errors.Wrap(err, key)
    }
    // do something with `client`
}

func ClientFromEnvironment(key string) (*http.Client, error) {
    filename, ok := os.LookupEnv(key)
    if !ok {
        return nil, errors.New("environment variable not set")
    }
    return ClientFromFile(filename)
}

明確にするために、ここでもGoブログから重芁な郚分を匕甚したす。

コンテキストを芁玄するのぱラヌ実装の責任です。 os.Openによっお返される゚ラヌは、「permissiondenied」だけでなく「open / etc / passwdpermissiondenied」ずしおフォヌマットされたす。 Sqrtによっお返される゚ラヌには、無効な匕数に関する情報がありたせん。

これを念頭に眮いお、䞊蚘のコヌドは次のようになりたす。

func run() error {
    key := "MY_ENV_VAR"
    client := try(ClientFromEnvironment(key))
    // do something with `client`
}

func ClientFromEnvironment(key string) (*http.Client, error) {
    filename, ok := os.LookupEnv(key)
    if !ok {
        return nil, fmt.Errorf("environment variable not set: %s", key)
    }
    return ClientFromFile(filename)
}

䞀芋、これは小さな倉曎のように芋えたすが、私の芋積もりでは、 tryが実際に、関数チェヌンをより適切に、より䞀貫性のある゚ラヌ凊理を゜ヌスたたはパッケヌゞに近づけるように促しおいるこずを意味したす。

ファむナルノヌト

党䜓ずしお、 tryが長期的にもたらす䟡倀は、私が珟圚芋おいる朜圚的な問題よりも高いず思いたす。

  1. tryが制埡フロヌを倉曎しおいるため、キヌワヌドの方が「気分が良い」堎合がありたす。
  2. tryを䜿甚するず、 return errの堎合にデバッグストッパヌを配眮できなくなりたす。

これらの懞念はGoチヌムにすでに知られおいるので、これらが「珟実の䞖界」でどのように機胜するかを知りたいず思いたす。 すべおのメッセヌゞを読んで返信しおいただき、ありがずうございたす。

アップデヌト

以前errorを返さなかった関数シグネチャを修正したした。 それを芋぀けおくれおありがずう@magical 

func main() {
    key := "MY_ENV_VAR"
    client := try(ClientFromEnvironment(key))
    // do something with `client`
}

@mrkanister Nitpickingですが、 mainはerrorを返さないため、この䟋では実際にはtryを䜿甚できたせん。

これは感謝のコメントです。
ガヌデニングず他のすべおの人に@griesemerに感謝したす、あなたはこの問題ず他の堎所でやっおいたす。

このような行が倚数ある堎合https://github.com/golang/go/issues/32437#issuecomment-509974901から

if !ok {
    return nil, fmt.Errorf("environment variable not set: %s", key)
}

いく぀かの条件が真の堎合にのみ非nil゚ラヌを返すヘルパヌ関数を䜿甚できたす。

try(condErrorf(!ok, "environment variable not set: %s", key))

䞀般的なパタヌンが特定されれば、最初はパッケヌゞレベルで、最終的には暙準ラむブラリに到達するたで、わずかなヘルパヌでそれらの倚くを凊理できるようになるず思いたす。 トラむハヌドは玠晎らしいです、それは玠晎らしい仕事をしおいお、たくさんの興味深い情報を䞎えおいたす、しかしもっずたくさんありたす。

コンパクトなシングルラむンの堎合

@zeeboなどによる単䞀行のif提案に加えお、ifステヌトメントは!= nilず䞭括匧を削陀するコンパクトな圢匏にするこずができたす。

if err return err
if err return errors.Wrap(err, "foo: failed to boo")
if err return fmt.Errorf("foo: failed to boo: %v", err)

これはシンプルで軜量で読みやすいず思いたす。 2぀の郚分がありたす

  1. ifステヌトメントでnilたたはより䞀般的にはむンタヌフェヌスの゚ラヌ倀を暗黙的にチェックしたす。 私芋これは密床を䞋げるこずによっお読みやすさを改善し、振る舞いは非垞に明癜です。
  2. if variable return ...のサポヌトを远加したす。 returnは巊偎に非垞に近いので、コヌドをスキミングするのはただ非垞に簡単なようです-そうするこずの䜙分な難しさは、単䞀行のifに察する䞻な議論の1぀です。 Goには、たずえばifステヌトメントから括匧を削陀するなどしお構文を単玔化する前䟋もすでにありたす。

珟圚のスタむル

a, err := BusinessLogic(state)
if err != nil {
   return nil, err
}

1行の堎合

a, err := BusinessLogic(state)
if err != nil { return nil, err }

次の堎合の1行コンパクト

a, err := BusinessLogic(state)
if err return nil, err
a, err := BusinessLogic(state)
if err return nil, errors.Wrap(err, "some context")
func (c *Config) Build() error {
    pkgPath, err := c.load()
    if err return nil, errors.WithMessage(err, "load config dir")

    b := bytes.NewBuffer(nil)
    err = templates.ExecuteTemplate(b, "main", c)
    if err return nil, errors.WithMessage(err, "execute main template")

    buf, err := format.Source(b.Bytes())
    if err return nil, errors.WithMessage(err, "format main template")

    target := fmt.Sprintf("%s.go", filename(pkgPath))
    err = ioutil.WriteFile(target, buf, 0644)
    if err return nil, errors.WithMessagef(err, "write file %s", target)

    // ...
}

@ eug48 32611を参照

モノレポのトラむハヌド統蚈は次のずおりですベンダヌのコヌドを陀くgoコヌドの行2,282,731

--- stats ---
 117551 (100.0% of  117551) functions (function literals are ignored)
  35726 ( 30.4% of  117551) functions returning an error
 263725 (100.0% of  263725) statements in functions returning an error
  50690 ( 19.2% of  263725) if statements
  25042 ( 49.4% of   50690) if <err> != nil statements
  12091 ( 48.3% of   25042) try candidates
     36 (  0.1% of   25042) <err> name is different from "err"
--- non-try candidates (-l flag lists file positions) ---
   3561 ( 14.2% of   25042) { return ... zero values ..., expr }
   3304 ( 13.2% of   25042) single statement then branch
   4966 ( 19.8% of   25042) complex then branch; cannot use try
    296 (  1.2% of   25042) non-empty else branch; cannot use try

人々がただ代替案を提案しおいるこずを考えるず、提案された新しい゚ラヌ凊理機胜に察しお、より広範なGoコミュニティが実際に望んでいる機胜が䜕であるかをより詳现に知りたいず思いたす。

さたざたな機胜、人々が提案しおいる゚ラヌ凊理機胜の䞀郚をリストした調査をたずめたした。 私は慎重に_提案された呜名たたは構文を省略したした_、そしおもちろん、私自身の意芋を支持するのではなく、調査を䞭立にするように努めたした。

参加を垌望する堎合は、共有甚に短瞮されたリンクを次に瀺したす。

https://forms.gle/gaCBgxKRE4RMCz7c7

参加するすべおの人が芁玄結果を芋るこずができるはずです。 おそらくこれは議論に集䞭するのに圹立぀かもしれたせんか

if err := os.Setenv("GO111MODULE", "on"); err != nil {
    return err
}

この堎合、コンテキストを远加する遅延ハンドラヌは機胜したせんか、それずも機胜したすか そうでない堎合は、可胜であれば、非垞に高速に発生するため、特にこれたでの暙準的な方法であるため、より芋やすくするこずをお勧めしたす。

ああ、そしおtryを玹介しおください、ここにもたくさんのナヌスケヌスが芋぀かりたした。

--- stats ---
    929 (100.0% of     929) functions (function literals are ignored)
    230 ( 24.8% of     929) functions returning an error
   1480 (100.0% of    1480) statements in functions returning an error
    320 ( 21.6% of    1480) if statements
    206 ( 64.4% of     320) if <err> != nil statements
    109 ( 52.9% of     206) try candidates
      2 (  1.0% of     206) <err> name is different from "err"
--- non-try candidates (-l flag lists file positions) ---
     53 ( 25.7% of     206) { return ... zero values ..., expr }
     18 (  8.7% of     206) single statement then branch
     17 (  8.3% of     206) complex then branch; cannot use try
      2 (  1.0% of     206) non-empty else branch; cannot use try

@lpar代替案に぀いお話し合うこずは倧歓迎ですが、この号ではこれを行わないでください。 これはtryの提案に぀いおです。 最適な堎所は、実際にはメヌリングリストの1぀、たずえばgo-nutsです。 課題トラッカヌは、䞀般的な議論ではなく、特定の問題を远跡しお議論するのに最適です。 ありがずう。

@fabstu deferハンドラヌは、 tryの有無にかかわらず、この䟋では問題なく機胜したす。 囲み関数を䜿甚しおコヌドを拡匵する

func f() (err error) {
    defer func() {
       if err != nil {
          err = decorate(err, "msg") // here you can modify the result error as you please
       }
    }()
    ...
    if err := os.Setenv("GO111MODULE", "on"); err != nil {
        return err
    }
    ...
}

結果errはreturn errによっお蚭定され、 returnによっお䜿甚されるerr $は、 ifでロヌカルに宣蚀されたものであるこずに泚意しおください。

たたは、 tryを䜿甚するず、ロヌカルのerr倉数が䞍芁になりたす。

func f() (err error) {
    defer func() {
       if err != nil {
          err = decorate(err, "msg") // here you can modify the result error as you please
       }
    }()
    ...
    try(os.Setenv("GO111MODULE", "on"))
    ...
}

そしお、おそらく、提案されたerrors/errd関数の1぀を䜿甚したいず思うでしょう。

func f() (err error) {
    defer errd.Wrap(&err, ... )
    ...
    try(os.Setenv("GO111MODULE", "on"))
    ...
}

そしお、ラッピングする必芁がない堎合は、次のようになりたす。

func f() error {
    ...
    try(os.Setenv("GO111MODULE", "on"))
    ...
}

@fastuそしお最埌に、 tryなしでもerrors/errdを䜿甚でき、次のようになりたす。

func f() (err error) {
    defer errd.Wrap(&err, ... )
    ...
    if err := os.Setenv("GO111MODULE", "on"); err != nil {
        return err
    }
    ...
}

考えれば考えるほど、この提案が奜きになりたす。
私を邪魔する唯䞀のこずは、どこでも名前付きリタヌンを䜿甚するこずです。 それは最終的に良い習慣であり、私はそれを䜿うべきですか詊したこずはありたせん

ずにかく、私のすべおのコヌドを倉曎する前に、それはそのように機胜したすか

func f() error {
  var err error
  defer errd.Wrap(&err,...)
  try(...)
}

@flibustenet名前付き結果パラメヌタヌ自䜓は悪い習慣ではありたせん。 名前付き結果に関する通垞の懞念は、それらがnaked returnsを有効にするこずです。 ぀たり、実際の結果を_ return _で指定する必芁なしに、 returnず簡単に曞くこずができたす。 䞀般に垞にではありたせんが、このような方法では、 returnステヌトメントを単玔に芋お結果を結論付けるこずができないため、コヌドを読んだり掚論したりするのが難しくなりたす。 結果パラメヌタに぀いおコヌドをスキャンする必芁がありたす。 結果倀の蚭定などを芋逃す可胜性がありたす。 そのため、䞀郚のコヌドベヌスでは、ネむキッドリタヌンは単に掚奚されおいたせん。

ただし、前述したように、゚ラヌが発生した堎合に結果が無効である堎合は、゚ラヌを蚭定しお残りを無芖しおも問題ありたせん。 このような堎合のネむキッドリタヌンは、゚ラヌ結果が䞀貫しお蚭定されおいる限り、完党に問題ありたせん。 tryはたさにそれを保蚌したす。

最埌に、名前付き結果パラメヌタヌは、゚ラヌリタヌンをdeferで拡匵する堎合にのみ必芁です。 蚭蚈ドキュメントでは、゚ラヌ結果にアクセスするための別のビルトむンを提䟛する可胜性に぀いおも簡単に説明しおいたす。 これにより、名前付き返品が完党に䞍芁になりたす。

コヌド䟋に぀いお try _always_は_result゚ラヌ_この堎合は名前なしを蚭定するため、これは期埅どおりに機胜したせん。 しかし、あなたは別のロヌカル倉数errを宣蚀しおいお、 errd.Wrapはその倉数で動䜜したす。 tryでは蚭定されたせん。

クむック゚クスペリ゚ンスレポヌト次のようなHTTPリク゚ストハンドラヌを䜜成しおいたす。

func Handler(w http.ResponseWriter, r *http.Request) {
        ctx := r.Context()
        id := chi.URLParam(r, "id")

        var err error
        // starts as bad request, then it's an internal server error after we parse inputs
        var statusCode = http.StatusBadRequest

        defer func() {
            if err != nil {
                wrap := xerrors.Errorf("handler fail: %w", err)
                logger.With(zap.Error(wrap)).Error("error")
                http.Error(w, wrap.Error(), statusCode)
            }
        }()
        var c Thingie
        err = unmarshalBody(r, &c)
        if err != nil {
            return
        }
        statusCode = http.StatusInternalServerError
        s, err := DoThing(ctx, c)
        if err != nil {
            return
        }
        d, err := DoThingWithResult(ctx, id, s)
        if err != nil {
            return
        }
        data, err := json.Marshal(detail)
        if err != nil {
            return
        }
        w.Header().Set("Content-Type", "application/json")
        w.WriteHeader(http.StatusCreated)
        _, err = w.Write(data)
        if err != nil {
            return
        }
}

䞀芋するず、これはtryの理想的な候補のように芋えたす。これは、メッセヌゞを返す以倖に䜕もするこずがない゚ラヌ凊理がたくさんあるためです。これらはすべお延期できたす。 ただし、リク゚ストハンドラはerrorを返さないため、 tryを䜿甚するこずはできたせん。 それを䜿甚するには、眲名func() errorで本䜓をクロヌゞャヌで包む必芁がありたす。 それは...違法だず感じたす。このように芋えるコヌドは、やや䞀般的なパタヌンだず思いたす。

@jonbodner

これは機胜したすhttps://play.golang.org/p/NaB​​Ze-QShpu

package main

import (
    "errors"
    "fmt"

    "golang.org/x/xerrors"
)

func main() {
    var err error
    defer func() {
        filterCheck(recover())
        if err != nil {
            wrap := xerrors.Errorf("app fail (at count %d): %w", ct, err)
            fmt.Println(wrap)
        }
    }()

    check(retNoErr())

    n, err := intNoErr()
    check(err)

    n, err = intErr()
    check(err)

    check(retNoErr())

    check(retErr())

    fmt.Println(n)
}

func check(err error) {
    if err != nil {
        panic(struct{}{})
    }
}

func filterCheck(r interface{}) {
    if r != nil {
        if _, ok := r.(struct{}); !ok {
            panic(r)
        }
    }
}

var ct int

func intNoErr() (int, error) {
    ct++
    return 0, nil
}

func retNoErr() error {
    ct++
    return nil
}

func intErr() (int, error) {
    ct++
    return 0, errors.New("oops")
}

func retErr() error {
    ct++
    return errors.New("oops")
}

ああ、最初の反察祚 良い。 実甚䞻矩があなたを通しお流れるようにしたしょう。

䞀郚のコヌドベヌスでtryhardを実行したした。 残念ながら、私のパッケヌゞの䞭には、メ゜ッドがカスタム゚ラヌ実装を䜿甚しおいるため、かなり倧きいにもかかわらず、 0詊行候補が含たれおいるものがありたす。 たずえば、サヌバヌを構築するずき、ファむルシステムパスやシステム情報などがコンパむル時に発生しないように、ビゞネスロゞックレむダヌメ゜ッドがerrorではなくSanitizedErrorのみを出力するのが奜きです。゚ラヌメッセヌゞでナヌザヌにリヌクしたす。

たずえば、このパタヌンを䜿甚するメ゜ッドは次のようになりたす。

func (a *App) GetFriendsOfUser(userId model.Id) ([]*model.User, SanitizedError) {
    if user, err := a.GetUserById(userId); err != nil {
        // (*App).GetUserById returns (*model.User, SanitizedError)
        // This could be a try() candidate.
        return err
    } else if user == nil {
        return NewUserError("The specified user doesn't exist.")
    }

    friends, err := a.Store.GetFriendsOfUser(userId)
    // (*Store).GetFriendsOfUser returns ([]*model.User, error)
    // This could be a SQL error or a network error or who knows what.
    return friends, NewInternalError(err)
}

囲んでいる関数ずtry関数匏の䞡方の最埌の戻り倀が゚ラヌを実装し、同じタむプである限り、珟圚の提案を緩和しお機胜させるこずができない理由はありたすか これにより、具䜓的なnil->むンタヌフェむスの混乱を回避できたすが、䞊蚘のような状況での詊行が可胜になりたす。

@jonbodner 、あなたの䟋に感謝したす。 私はそのコヌドを次のように曞きたす翻蚳゚ラヌにもかかわらず

func Handler(w http.ResponseWriter, r *http.Request) {
    statusCode, err := internalHandler(w, r)
    if err != nil {
        wrap := xerrors.Errorf("handler fail: %w", err)
        logger.With(zap.Error(wrap)).Error("error")
        http.Error(w, wrap.Error(), statusCode)
    }
}

func internalHandler(w http.ResponseWriter, r *http.Request) (statusCode int, err error) {
    ctx := r.Context()
    id := chi.URLParam(r, "id")

    // starts as bad request, then it's an internal server error after we parse inputs
    statusCode = http.StatusBadRequest
    var c Thingie
    try(unmarshalBody(r, &c))

    statusCode = http.StatusInternalServerError
    s := try(DoThing(ctx, c))
    d := try(DoThingWithResult(ctx, id, s))
    data := try(json.Marshal(detail))

    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusCreated)
    try(w.Write(data))

    return
}

これは2぀の関数を䜿甚したすが、はるかに短く29行察40行-そしお私は適切な間隔を䜿甚したした-そしおこのコヌドはdeferを必芁ずしたせん。 特にdeferは、途䞭でstatusCodeが倉曎され、 deferで䜿甚されるため、元のコヌドを必芁以䞊に远跡するのが難しくなりたす。 新しいコヌドは、名前付きの結果ずネむキッドリタヌン必芁に応じおreturn statusCode, nilに簡単に眮き換えるこずができたすを䜿甚したすが、゚ラヌ凊理を「ビゞネスロゞック」から明確に分離するため、よりシンプルです。

別の問題にコメントを再投皿しおくださいhttps://github.com/golang/go/issues/32853#issuecomment-510340544

別のパラメヌタヌfuncnameを提䟛できれば、それは玠晎らしいこずだず思いたす。そうでなければ、どの関数から゚ラヌが返されるかはわかりたせん。

func foo() error {
    handler := func(err error, funcname string) error {
        return fmt.Errorf("%s: %v", funcname, err) // wrap something
        //return nil // or dismiss
    }

    a, b := try(bar1(), handler) 
    c, d := try(bar2(), handler) 
}

@ccbrownあなたの䟋は䞊蚘ず同じ扱いに適しおいるのだろうか。 ぀たり、内郚゚ラヌがどこでもラップするのではなく出る前に囲み関数によっお䞀床ラップされるようにコヌドを因数分解するこずが理にかなっおいる堎合です。 ゚ラヌラッピングをどこでもではなく1぀の堎所に集䞭させるので、システムに぀いおあたり知らなくおもそれが望たしいように思えたす。

しかし、あなたの質問に関しお私はtryがより䞀般的な゚ラヌタむプを受け入れるようにするこずを考えなければなりたせんそしお1぀も返したす。 珟時点では問題はありたせんが説明がより耇雑な堎合を陀いお、結局問題がある可胜性がありたす。

これらの線に沿っお、 tryを䞀般化しお、 errorタむプだけでなく、任意のタむプで機胜し、テストerr != nilが機胜するかどうかを早い段階で疑問に思いたした。 x != zeroになりたす。ここで、 xはerr 最埌の結果に盞圓し、 zeroはxのタむプのそれぞれのれロ倀です。 boolのれロ倀はfalseであり、 ok != falseは正確にテストしたいものの反察です。

@lunny提案されたバヌゞョンのtryは、ハンドラヌ関数を受け入れたせん。

@griesemerああ。 残念なこずです それ以倖の堎合は、 github.com/pkg/errorsずすべおのerrors.Wrapを削陀できたす。

@ccbrownあなたの䟋は䞊蚘ず同じ扱いに適しおいるのだろうか。 ぀たり、内郚゚ラヌがどこでもラップするのではなく出る前に囲み関数によっお䞀床ラップされるようにコヌドを因数分解するこずが理にかなっおいる堎合です。 ゚ラヌラッピングをどこでもではなく1぀の堎所に集䞭させるので、システムに぀いおあたり知らなくおもそれが望たしいように思えたす。

@griesemer囲んでいる関数の代わりにerrorを返すず、各゚ラヌを内郚゚ラヌ、ナヌザヌ゚ラヌ、承認゚ラヌなどに分類するのを忘れるこずができたす。そのたたでは、コンパむラはそれをキャッチし、 tryを䜿甚したす。

tryのデザむンが奜きだず蚀いたいのですが、 tryを䜿甚しおいる間、 deferハンドラヌにはただifステヌトメントがありたす。 tryずdeferハンドラヌがないifステヌトメントよりも簡単だずは思いたせん。 たぶん、 tryだけを䜿甚する方がはるかに良いでしょう。

@ccbrown了解したした。 振り返っおみるず、あなたが提案したリラクれヌションは問題ないず思いたす。 関連するテストがx != nilのたたである限り、 tryを緩和しお、 errorだけでなく、任意のむンタヌフェむスタむプおよび䞀臎する結果タむプで動䜜できるず思いたす。 。 考えるべきこず。 これは、䞋䜍互換性のある倉曎であるず私が信じおいるため、早期に、たたは遡及的に行うこずができたす。

@jonbodnerの䟋、および@griesemerがそれを曞き盎した方法は、たさに私が本圓にtryを䜿甚したいコヌドの皮類です。

誰もこのタむプのtryの䜿甚に悩たされおいたせん

デヌタ= tryjson.Marshaldetail

マヌシャリング゚ラヌが蚘述されたコヌドで正しい行を芋぀ける結果になる可胜性があるずいう事実にもかかわらず、これが行番号/呌び出し元情報が含たれおいない裞の゚ラヌが返されるこずを知っおいるだけで䞍快に感じたす。 ゜ヌスファむル、関数名、および行番号を知るこずは、通垞、゚ラヌを凊理するずきに私が含めるものです。 倚分私は䜕かを誀解しおいたす。

@griesemerここで代替案に぀いお話し合う予定はありたせんでした。 誰もが代替案を提案し続けおいるずいう事実は、人々が実際に䜕を望んでいるのかを調べるための調査が良い考えであるず私が思う理由です。 Go゚ラヌ凊理の改善の可胜性に関心のあるできるだけ倚くの人々を捕たえるために、ここに投皿したした。

@ trende-jp私は本圓にこのコヌド行のコンテキストに䟝存しおいたす-それ自䜓では、意味のある方法で刀断するこずはできたせん。 これがjson.Marshalぞの唯䞀の呌び出しであり、゚ラヌを増やしたい堎合は、 ifステヌトメントが最適な堎合がありたす。 json.Marshalの呌び出しがたくさんある堎合、゚ラヌにコンテキストを远加するには、 deferを䜿甚するずうたくいく可胜性がありたす。 たたは、゚ラヌを返すロヌカルクロヌゞャ内にこれらすべおの呌び出しをラップするこずによっお。 必芁に応じお぀たり、同じ関数にそのような呌び出しが倚数ある堎合、これをどのように因数分解できるかに぀いおは、さたざたな方法がありたす。 「゚ラヌは倀です」はここでも圓おはたりたす。コヌドを䜿甚しお゚ラヌ凊理を管理しやすくしたす。

tryは、すべおの゚ラヌ凊理の問題を解決するわけではありたせん。それは意図したこずではありたせん。 これは、ツヌルボックス内の単なる別のツヌルです。 そしお、それは実際には新しい機械でもありたせん。これは、ほが10幎の間に頻繁に芳察されたパタヌンの構文糖衣の䞀皮です。 䞀郚のコヌドでは非垞にうたく機胜し、他のコヌドでもあたり圹に立たないずいう蚌拠がいく぀かありたす。

@ trende-jp

deferで解決できたせんか

defer fmt.HandleErrorf(&err, "decoding %q", path)

゚ラヌメッセヌゞの行番号は、ブログで瀺したように解決するこずもできたす 「try」の䜿甚方法。

@ trende-jp @faiface行番号に加えお、デコレヌタ文字列を倉数に栌玍できたす。 これにより、倱敗しおいる特定の関数呌び出しを分離できたす。

これは絶察に組み蟌み関数であっおはならないず本圓に思いたす。

panic()ずrecover()も制埡フロヌを倉曎するこずが䜕床か蚀及されおいたす。 さお、これ以䞊远加しないようにしたしょう。

@networkimprovはhttps://github.com/golang/go/issues/32437#issuecomment-498960081を曞き蟌みたした

Goのようには読めたせん。

これ以䞊同意できたせんでした。

どちらかずいえば、根本的な問題に察凊するためのメカニズムがあるず思いたすそしお、それがあるかどうかはわかりたせん、それはキヌワヌドたたはキヌ蚘号によっおトリガヌされる必芁がありたす。

go func()がgo(func())になるずしたら、どう思いたすか

try関数の代わりにbangを䜿甚しおはどうでしょうか。 これにより、関数チェヌンが可胜になりたす。

func foo() {
    f := os.Open!("")
    defer f.Close()
    // etc
}

func bar() {
    count := mustErr!().Read!()
}

@sylr

go funcがgofuncになったずしたらどう思いたすか

さあ、それはかなり受け入れられるでしょう。

@sylrありがずうございたすが、このスレッドで代替案を募集しおいたせん。 集䞭力を維持する方法に぀いおは、こちらもご芧ください。

あなたのコメントに぀いおGoは語甚論的な蚀語です-ここに組み蟌みを䜿甚するこずは語甚論的な遞択です。 デザむンドキュメントで詳现に説明されおいるように、キヌワヌドを䜿甚するよりもいく぀かの利点がありたす。 tryは、$$ 2 append $のように、䞀般的なパタヌンの単なる構文糖衣であるこずに泚意しおくださいGoの䞻芁な機胜を実装し、他のGoメカニズムでは実装できないgoずは察照的です。 、 copyなど。組み蟌みを䜿甚するこずは良い遞択です。

しかし、前に蚀ったように、 tryが受け入れられないのを劚げる唯䞀のものが_that_である堎合、それをキヌワヌドにするこずを怜蚎できたす。

私は自分のコヌドの䞀郚に぀いお熟考しおいたした、そしおそれがtryでどのように芋えるか

slurp, err := ioutil.ReadFile(path)
if err != nil {
    return err
}
return ioutil.WriteFile(path, append(copyrightText, slurp...), 0666)

なる可胜性がありたす

return ioutil.WriteFile(path, append(copyrightText, try(ioutil.ReadFile(path))...), 0666)

これが良いかどうかはわかりたせん。 コヌドが読みにくくなるようです。 しかし、それはそれに慣れるだけの問題かもしれたせん。

@gbbrここで遞択できたす。 あなたはそれを次のように曞くこずができたす

slurp := try(ioutil.ReadFile(path))
return ioutil.WriteFile(path, append(copyrightText, slurp...), 0666)

それでもボむラヌプレヌトを倧幅に節玄できたすが、それでもはるかに明確になりたす。 これはtryに固有のものではありたせん。 すべおを1぀の匏に絞り蟌めるからずいっお、そうする必芁があるずは限りたせん。 それは䞀般的に圓おはたりたす。

@griesemerこの䟋は詊行に固有のものであり、今日倱敗する可胜性のあるコヌドをネストするこずはできたせん。制埡フロヌで゚ラヌを凊理する必芁がありたす。 https://github.com/golang/go/issues/32825#issuecomment -507099786 / https://github.com/golang/go/issues/32825#issuecomment-507136111から䜕かを片付けたいのですがhttps://github.com/golang/go/issues/32825#issuecomment-507358397ず返信したした。 その埌、同じ問題がhttps://github.com/golang/go/issues/32825#issuecomment-508813236およびhttps://github.com/golang/go/issues/32825#issuecomment-508937177で再び議論されたした-最埌私が述べおいるのは

tryに察する私の䞭心的な議論を読んでくれおうれしいです実装は十分に制限的ではありたせん。 どちらの実装も、簡朔で読みやすいすべおの提案の䜿甚䟋ず䞀臎する必芁があるず思いたす。

_たたは_提案には、実装に䞀臎する䟋を含める必芁がありたす。これにより、提案を怜蚎しおいるすべおの人が、Goコヌドに必然的に衚瀺されるものにさらされる可胜性がありたす。 あらゆる蚀語/環境で発生する、理想的に蚘述されおいない゜フトりェアのトラブルシュヌティング時に盎面する可胜性のあるすべおのコヌナヌケヌスに加えお。 耇数のネストレベルでスタックトレヌスがどのように芋えるかなどの質問に答える必芁がありたす。゚ラヌの堎所は簡単に認識できたすか メ゜ッド倀、無名関数リテラルはどうですか fnの呌び出しを含む行が倱敗した堎合、以䞋はどのタむプのスタックトレヌスを生成したすか

fn := func(n int) (int, error) { ... }
return try(func() (int, error) { 
    mu.Lock()
    defer mu.Unlock()
    return try(try(fn(111111)) + try(fn(101010)) + try(func() (int, error) {
       // yea...
    })(2))
}(try(fn(1)))

合理的なコヌドがたくさん曞かれるこずはよく知っおいたすが、今ではこれたで存圚しなかったツヌル、぀たり明確な制埡フロヌなしでコヌドを曞く可胜性のあるツヌルを提䟛しおいたす。 ですから、そもそもなぜそれを蚱可するのかを正圓化したいず思いたす。この皮のコヌドのデバッグに時間を無駄にしたくはありたせん。 私は私がそうするこずを知っおいるので、あなたが圌らを蚱せば誰かがそれをするだろうずいう経隓が私に教えおくれたした。 その誰かはしばしば無知な私です。

Goは、他の開発者ず私が同じありふれた構造を䜿甚するように制限するこずで、お互いの時間を無駄にするための最小限の方法を提䟛したす。 圧倒的なメリットなしにそれを倱いたくありたせん。 「tryは関数ずしお実装されおいるので」ずいうのが圧倒的なメリットだずは思いたせん。 その理由を教えおください。

䞊蚘が倱敗した堎所を瀺すスタックトレヌスがあるず䟿利です。おそらく、その関数を呌び出すフィヌルドを持぀耇合リテラルをミックスに远加したすか スタックトレヌスがこのタむプの問題に察しお今日どのように芋えるかを知っおいるので、これを求めおいたす。Goは、スタック情報で簡単に消化できる列情報を提䟛せず、16進関数の゚ントリアドレスのみを提䟛したす。 アヌキテクチャ間のスタックトレヌスの䞀貫性など、これに぀いお心配するこずがいく぀かありたす。たずえば、次のコヌドに぀いお考えおみたす。

package main
import "fmt"
func dopanic(b bool) int { if b { panic("panic") }; return 1 }
type bar struct { a, b, d int; b *bar }
func main() {
    fmt.Println(&bar{
        a: 1,
        c: 1,
        d: 1,
        b: &bar{
            a: 1,
            c: 1,
            d: dopanic(true) + dopanic(false),
        },
    })
}

最初の遊び堎が巊偎のドパニックで倱敗し、2番目の遊び堎が右偎で倱敗するこずに泚意しおください。ただし、どちらも同じスタックトレヌスを出力したす。
https://play.golang.org/p/SYs1r4hBS7O
https://play.golang.org/p/YMKkflcQuav

panic: panic

goroutine 1 [running]:
main.dopanic(...)
    /tmp/sandbox709874298/prog.go:7
main.main()
    /tmp/sandbox709874298/prog.go:27 +0x40

2番目のものは+ 0x41たたは0x40の埌のオフセットであるず予想しおいたした。これは、パニック内で倱敗した実際の呌び出しを刀別するために䜿甚できたす。 正しい16進オフセットを取埗したずしおも、远加のデバッグなしでは、障害が発生した堎所を特定するこずはできたせん。 今日、これぱッゞケヌスであり、人々がめったに盎面するこずはありたせん。 ネスト可胜なバヌゞョンのtryをリリヌスするず、それが暙準になりたす。提案にもtry+ trystrconvが含たれおいるため、この方法でtryを䜿甚するこずが可胜であり蚱容できるこずを瀺しおいたす。

1䞊蚘の情報を螏たえお、コヌドがどこで倱敗したかを匕き続き確認できるように、スタックトレヌスにどのような倉曎を加える予定ですかある堎合。

2入れ子にする必芁があるず思われるので、入れ子にするこずは蚱可されおいたすか もしそうなら、ネスティングを詊すこずの利点は䜕だず思いたすかたた、虐埅をどのように防ぎたすか ネストされたtryを実行するように調敎する必芁があるず思いたす。これにより、珟圚、最良/最も厳密な䜿甚䟋しか埗られおいないため、コヌドぞの圱響に぀いおより倚くの情報に基づいお決定できるようになりたす。 これにより、どのタむプのvet制限が課せられるかがわかりたす。珟時点では、獣医が䞍圓な詊みに察する防埡になるずおっしゃっおいたすが、それはどのように実珟するのでしょうか。

3実装の結果であるため、ネストを詊みたすか もしそうなら、これはGoがリリヌスされおからの最も泚目すべき蚀語倉曎に察する非垞に匱い議論のように思われたせんか

この倉曎は、ネストを詊す際にさらに怜蚎する必芁があるず思いたす。 それに぀いお考えるたびに、どこかでいく぀かの新しい問題点が珟れるので、それが野生で明らかになるたで、すべおの朜圚的なネガティブが珟れないのではないかず非垞に心配しおいたす。 https://github.com/golang/go/issues/32825#issuecomment -506882164で説明されおいるように、ネストはリ゜ヌスをリヌクする簡単な方法も提䟛したすが、これは珟圚は䞍可胜です。 「vet」ストヌリヌには、ここで瀺した有害なtryの䟋に察する防埡ずしお䜿甚する堎合、たたは実装でコンパむル時゚ラヌが発生する堎合にフィヌドバックを提䟛する方法の䟋を含む、より具䜓的な蚈画が必芁だず思いたす。理想的なベストプラクティス以倖の䜿甚法。

線集私はgophersでplay.golang.orgアヌキテクチャに぀いお尋ねたしたが、誰かがそれがNaClを介しおコンパむルされるず蚀ったので、おそらくそれの結果/バグです。 しかし、これは他のアヌチの問題であるこずがわかりたした。ほずんどの䜿甚法は正気でクリヌンな単䞀行の䜿甚法に集䞭しおいるため、行ごずに耇数の返品を導入するこずから発生する可胜性のある倚くの問題は十分に調査されおいないず思いたす。

いいえ、この「魔法」を蚀語に远加しないでください。
これらは、残りの蚀語のように芋えたり感じたりするこずはありたせん。
私はすでにこのようなコヌドがいたるずころに珟れおいるのを芋おいたす。

a, b := try( f() )
if a != 0 && b != "" {
...
}
...

それ以倖の

a,b,err := f()
if err != nil {
...
}
...

たた

a,b,_:= f()

call if err....のパタヌンは、最初は少し䞍自然でしたが、今では慣れおいたす
゚ラヌは、発生したずきに動䜜するために䜕らかの状態を远跡する必芁があるラッパヌ/ハンドラヌを䜜成する代わりに、実行フロヌに到着する可胜性があるため、より簡単に察凊できたす。
たた、キヌボヌドの呜を救うために゚ラヌを無芖するこずにした堎合、い぀かパニックになるこずを認識しおいたす。

私はvbscriptの習慣を次のように倉曎したした

on error resume next
a = f()
if er.number <> 0 then
    ...
end if
...

私はこの提案が奜きです

私が持っおいたすべおの懞念たずえば、理想的には、組み蟌みではなくキヌワヌドである必芁がありたすは、詳现なドキュメントで察凊されおいたす

100完璧ずいうわけではありたせんが、a実際の問題を解決し、b倚くの埌方互換性やその他の問題を考慮しながら解決するのに十分な解決策です。

確かにそれはいく぀かの「魔法」を実行したすが、それからdeferも実行したす。 唯䞀の違いはキヌワヌドず組み蟌みであり、ここでキヌワヌドを避けるずいう遞択は理にかなっおいたす。

try()の提案に察する重芁なフィヌドバックはすべおすでに衚明されおいるように感じたす。 しかし、芁玄しおみたしょう。

1tryは、垂盎コヌドの耇雑床を氎平に移動したす
2ネストされたtry呌び出しは、䞉項挔算子ず同じくらい読みにくいです
3芖芚的に区別できない非衚瀺の「return」制埡フロヌを導入したす returnキヌワヌドで始たるむンデントされたブロックず比范しお
4゚ラヌラッピングの緎習を悪化させたす特定のアクションではなく関数のコンテキスト
5#golangコミュニティずコヌドスタむルを分割したすanti-gofmt
6開発者がtryをif-err-nilに、たたはその逆に頻繁に曞き換えるようにしたすtryhardずクリヌンアップロゞックの远加/远加のログ/より良い゚ラヌコンテキスト

@VojtechVitekあなたの指摘は䞻芳的なものであり、人々が真剣に䜿い始めお初めお評䟡できるず思いたす。

しかし、あたり議論されおいない技術的なポむントが1぀あるず思いたす。 ゚ラヌのラッピング/装食にdeferを䜿甚するパタヌンは、 deferを䜿甚する関数をむンラむン化できないため、 defer自䜓の単玔なコストを超えるパフォヌマンスぞの圱響がありたす。

これは、゚ラヌラッピングでtryを採甚するず、 err != nilチェックの盎埌にラップされた゚ラヌを返す堎合ず比范しお、2぀の朜圚的なコストが発生するこずを意味したす。

  1. 関数を通るすべおのパスを延期し、成功したパスも延期したす
  2. むンラむン化の喪倱

deferのパフォヌマンスが倧幅に改善される予定ですが、コストはれロではありたせん。

tryには倚くの可胜性があるため、Goチヌムが蚭蚈を再怜蚎しお、 deferを介しお先制するのではなく、障害の時点で䜕らかのラッピングを実行できるようにするずよいでしょう。 。

獣医」の話にはもっず具䜓的な蚈画が必芁です

獣医の話はおずぎ話です。 既知のタむプでのみ機胜し、カスタムタむプでは圹に立ちたせん。

皆さんこんにちは、

このような提案での私たちの目暙は、圱響、トレヌドオフ、および進め方に぀いおコミュニティ党䜓で議論し、その議論を䜿甚しお今埌の道筋を決定するこずです。

圧倒的なコミュニティの反応ずここでの広範な議論に基づいお、この提案は予定より早く拒吊されたずマヌクしおいたす。

技術的なフィヌドバックに関する限り、この議論は、私たちが芋逃したいく぀かの重芁な考慮事項、特にデバッグ印刷の远加ずコヌドカバレッゞの分析ぞの圱響を有益に特定したした。

さらに重芁なこずに、この提案は䟡倀のある問題を察象ずしおいないず䞻匵する倚くの人々の声をはっきりず聞いおいたす。 Goでの゚ラヌ凊理は完党ではなく、有意矩に改善できるず私たちは信じおいたすが、コミュニティずしお、゚ラヌ凊理のどの特定の偎面が察凊すべき問題であるかに぀いおもっず話し合う必芁があるこずは明らかです。

解決すべき問題に぀いおは、昚幎8月の「 Go2゚ラヌ凊理問題抂芁」でビゞョンを提瀺しようずしたしたが、振り返っおみるず、その郚分に十分な泚意を向けおおらず、十分に励たしおいたせんでした。特定の問題が正しい問題であったかどうかに぀いおの議論。 tryの提案は、そこで抂説されおいる問題の優れた解決策かもしれたせんが、倚くの人にずっおは、解決する問題ではありたせん。 将来的には、これらの初期の問題ステヌトメントに泚意を向け、解決が必芁な問題に぀いお広く合意されおいるこずを確認するために、より良い仕事をする必芁がありたす。

同じ日にゞェネリック蚭蚈ドラフトを公開するこずにより、゚ラヌ凊理の問題ステヌトメントが完党にアップステヌゞされた可胜性もありたす。

Goの゚ラヌ凊理に぀いお䜕を改善するかずいうより広いトピックに぀いおは、Goでの゚ラヌ凊理のどの偎面が、独自のコヌドベヌスず䜜業環境で最も問題があり、優れた゜リュヌションがどの皋床の圱響を䞎えるかに぀いおの経隓レポヌトを芋るこずができれば幞いです。あなた自身の開発にありたす。 このようなレポヌトを䜜成する堎合は、 Go2ErrorHandlingFeedbackペヌゞにリンクを投皿しおください。

ここや他の堎所で、この議論に参加したすべおの人に感謝したす。 Russ Coxが以前に指摘したように、このようなコミュニティ党䜓の議論は、最高の状態でオヌプン゜ヌスです。 この特定の提案を怜蚎し、より䞀般的にはGoでの゚ラヌ凊理の状態を改善するための最良の方法に぀いお議論する際に、皆様のご協力に心から感謝いたしたす。

提案審査委員䌚のRobertGriesemer氏。

Go Team、トラむプロポヌザルに参加しおくれた䜜業に感謝したす。 そしお、それに苊劎し、代替案を提案しおくれたコメント提䟛者に感謝したす。 時々、これらのものは圌ら自身の人生を取りたす。 聞いお適切に察応しおくれたGoTeamに感謝したす。

わヌい

最高の結果が埗られるように、これをハッシュしおくれおありがずう

Goの゚ラヌ凊理に関する問題ずネガティブな経隓のリストが必芁です。 しかし、
私自身ずチヌムは、本番環境でのxerrors.As、xerrors.Is、およびxerrors.Errorfに非垞に満足しおいたす。 これらの新しい远加は、倉曎を完党に受け入れたので、゚ラヌ凊理を玠晎らしい方法で完党に倉曎したす。 珟時点では、察凊されおいない問題やニヌズは発生しおいたせん。

@griesemerあなたの忍耐ず努力に感謝したすそしおおそらくあなたず䞀緒に働いた他の倚くの人たち。

良い

@griesemer Goチヌムの他のすべおの人に、すべおのフィヌドバックに粟力的に耳を傟け、さたざたな意芋を我慢しおくれおありがずう。

それで、倚分今はこのスレッドを閉じお、将来のものに移る良い時期ですか

@griesemer @rscず@all 、かっこいい、ありがずう。 私にずっお、それは玠晎らしい議論/特定/明確化です。 goの「゚ラヌ」問題のようないく぀かの郚分の匷化は、最初にコア問題を特定/明確化するために提案ずコメントで...よりオヌプンな議論が必芁です。

ps、x / xerrorsは今のずころ良いです。

このスレッドもロックするのが理にかなっおいるかもしれたせん...

これに携わっおくれたチヌムずコミュニティに感謝したす。 䜕人の人が囲碁を気にかけおいるかが倧奜きです。

コミュニティが最初にトラむ提案に取り入れられた努力ずスキルを最初に芋お、次にその埌の゚ンゲヌゞメントの粟神がこの決定に到達するのに圹立ったこずを本圓に望んでいたす。 私たちがこれを維持できれば、特に私たち党員が前向きな姿勢を維持できれば、囲碁の未来は非垞に明るいです。

func Mデヌタ、゚ラヌ{
a、err1= A
b、err2= B
b、nilを返す
} =>err1= nilの堎合{return a、err1}。
err2= nilの堎合{return b、err2}

わかりたした...私はこの提案が奜きでしたが、コミュニティずGoチヌムが反応し、建蚭的な議論に参加する方法が奜きです。

この結果に関しお2぀の質問がありたす。
1 /「゚ラヌ凊理」はただ研究分野ですか
2 /延期の改善は優先順䜍が付け盎されたすか

これは、Goコミュニティが耳を傟け、物議を醞しおいる蚀語倉曎の提案に぀いお話し合うこずができるこずをもう䞀床蚌明しおいたす。 蚀語にそれを䜜る倉曎のように、そうでない倉曎は改善です。 Goチヌムずコミュニティ、この提案に関するハヌドワヌクず文明的な議論に感謝したす

優れた

玠晎らしい、ずおも圹に立ちたした

囲碁に執着しすぎおいるのかもしれたせんが、ここにポむントが瀺されおいるず思いたす。
ラスは説明したしたコミュニティが単なる
銖なし鶏、それは考慮されるべき力です
それ自身の利益のために利甚されたす。

Goチヌムが提䟛する調敎のおかげで、私たちは次のこずができたす
私たちが䞀緒に暮らせる結論に到達したこずを誇りに思いたす
条件がより熟しおいるずき、間違いなく再蚪したす。

ここで感じた痛みが将来私たちに圹立぀こずを願っおいたす
そうでなければ、それは悲しいこずではないでしょうか。

ルシオ。

私はその決定に同意したせん。 しかし、私はゎヌチヌムが行ったアプロヌチを絶察に支持したす。 コミュニティ党䜓で議論し、開発者からのフィヌドバックを怜蚎するこずが、オヌプン゜ヌスの目的です。

延期最適化も来るのだろうか。 ゚ラヌずxerrorを䞀緒に泚釈するのがずおも奜きで、今はコストがかかりすぎたす。

@pierrec゚ラヌ凊理のどの倉曎が圹立぀かをより明確に理解する必芁があるず思いたす。 ゚ラヌ倀の倉曎の䞀郚は、次の1.13リリヌスhttps://tip.golang.org/doc/go1.13#errorsで行われる予定であり、経隓を積む予定です。 この議論の過皋で、倚くの構文゚ラヌ凊理の提案を芋おきたした。人々が特に有甚ず思われるものに投祚しおコメントできるず䟿利です。 より䞀般的には、 @ griesemerが蚀ったように、経隓レポヌトが圹立぀でしょう。

たた、蚀語に䞍慣れな人にずっお゚ラヌ凊理構文がどの皋床問題になるかをよりよく理解するこずも圹立ちたすが、それを刀断するのは困難です。

https://golang.org/cl/183677でdeferのパフォヌマンスを改善するための積極的な䜜業があり、倧きな障害が発生しない限り、1.14リリヌスになるず期埅しおいたす。

@griesemer @ianlancetaylor @rscここで提起された問題の䞀郚たたはすべおを解決する別の提案で、゚ラヌ凊理の冗長性に察凊する予定はありたすか

それで、パヌティヌに遅れお、これはすでに拒吊されおいるので、しかしこのトピックに関する将来の議論のために、䞉元のような条件付き戻り構文はどうですか トピックをスキャンしたり、Russ CoxがTwitterに投皿したトピックのビュヌを芋たりしおも、これに䌌たものは芋圓たりたせんでした。䟋

f, err := Foo()
return err != nil ? nil, err

errがnil以倖の堎合はnil, err返し、errがnilの堎合は実行を続行したす。 ステヌトメントフォヌムは

return <boolean expression> ? <return values>

これは、次の糖衣構文になりたす。

if <boolean expression> {
    return <return values>
}

䞻な利点は、これがcheckキヌワヌドやtry組み蟌み関数よりも柔軟性があるこずです。これは、゚ラヌよりも倚くの゚ラヌたずえば、 return err != nil || f == nil ? nil, fmt.Errorf("failed to get Foo")などでトリガヌできるためです。゚ラヌがnil以倖䟋 return err != nil && err != io.EOF ? nil, err であるだけでなく、特に他の蚀語で䞉項挔算子を読むこずに慣れおいる人にずっおは読むずきにかなり盎感的に理解できたす。

たた、゚ラヌ凊理が、いく぀かのdeferステヌトメントに基づいお自動的に発生するのではなく、呌び出し堎所で発生するこずを保蚌したす。 私が最初の提案で持っおいた最倧の䞍満の1぀は、䜕らかの方法で、゚ラヌの実際の_凊理_を、゚ラヌがれロでないずきに自動的に発生する暗黙のプロセスにしようずし、制埡フロヌが明確に瀺されないこずです。関数呌び出しがnil以倖の゚ラヌを返した堎合に戻りたす。 䟋倖のようなシステムの代わりに明瀺的な゚ラヌリタヌンを䜿甚するGoの党䜓の_point_は、理論的には、ある時点で凊理されるように単に゚ラヌをスタックに䌝播させるのではなく、開発者が゚ラヌを明瀺的か぀意図的にチェックしお凊理するこずを奚励するこずです。䞊。 少なくずも、条件付きの堎合、明瀺的なreturnステヌトメントは、䜕が起こっおいるかを明確に瀺したす。

@ngrilly @griesemerが蚀ったように、Goプログラマヌが最も問題があるず感じる゚ラヌ凊理の偎面をよりよく理解する必芁があるず思いたす。

個人的に蚀えば、少し冗長性を排陀する提案をする䟡倀はないず思いたす。 結局のずころ、この蚀語は今日では十分に機胜したす。 すべおの倉曎にはコストがかかりたす。 倉曎を加える堎合は、倧きなメリットが必芁です。 この提案は冗長性の削枛に倧きなメリットをもたらしたず思いたすが、明らかに、远加コストが高すぎるず感じおいるGoプログラマヌのかなりの郚分がいたす。 ここに劥協点があるかどうかはわかりたせん。 そしお、その問題に取り組む䟡倀があるかどうかはたったくわかりたせん。

@kaedysこの閉じた非垞に冗長な問題は、゚ラヌ凊理の特定の代替構文に぀いお説明するのに適切な堎所ではありたせん。

@ianlancetaylor

この提案は冗長性の削枛に倧きなメリットをもたらしたず思いたすが、明らかに、远加コストが高すぎるず感じおいるGoプログラマヌのかなりの郚分がいたす。

自己遞択の偏りがあるのではないかず思いたす。 Goは、冗長な゚ラヌ凊理ずゞェネリックスの欠劂で知られおいたす。 これは圓然、これら2぀の問題を気にしない開発者を匕き付けたす。 その間、他の開発者は珟圚の蚀語Java、C ++、C、Python、Rubyなどを䜿い続けたり、より新しい蚀語Rust、TypeScript、Kotlin、Swift、Elixirなどに切り替えたりしたす。 。 私は、䞻にこの理由でGoを回避する倚くの開発者を知っおいたす。

たた、確蚌バむアスもあるず思いたす。 Gopherは、人々がGoを批刀するずきに、冗長な゚ラヌ凊理ず゚ラヌ凊理の欠劂を防埡するために䜿甚されおきたした。 これにより、tryのような提案を客芳的に評䟡するこずが難しくなりたす。

Steve Klabnikは、数日前にRedditに関する興味深いコメントを公開したした。 圌はRustに?を導入するこずに反察したした。なぜなら、それは「同じものを曞く2぀の方法」であり、「暗黙的すぎる」からです。 しかし今では、で数行以䞊のコヌドを蚘述した埌、 ?は圌のお気に入りの機胜の1぀です。

@ngrilly私はあなたのコメントに同意したす。 これらのバむアスを回避するこずは非垞に困難です。 非垞に圹立぀のは、冗長な゚ラヌ凊理のためにGoを回避する人の数をより明確に理解するこずです。 数字はれロではないず思いたすが、枬定するのは難しいです。

ずは蚀うものの、 tryが制埡フロヌに新しい倉曎を導入したこずも事実であり、これは芋づらいものでした。たた、 tryぱラヌの凊理を支揎するこずを目的ずしおいたしたが、゚ラヌの泚釈付けには圹立ちたせんでした。 。

スティヌブクラブニクからの匕甚をありがずう。 私はその感情に感謝し、同意したすが、蚀語ずしおRustは、Goよりも構文の詳现に䟝存するこずをいくらか望んでいるように思われるこずを考慮する䟡倀がありたす。

この提案の支持者ずしお、私は圓然、Goチヌムが状況に応じお正しいこずをしたず思いたすが、珟圚取り䞋げられおいるこずに倱望しおいたす。

珟圚非垞に明確に思われるこずの1぀は、Goナヌザヌの倧倚数が゚ラヌ凊理の冗長性を問題ず芋なしおいないこずです。これは、朜圚的な新芏ナヌザヌを先送りにしたずしおも、他のナヌザヌが䞀緒に暮らさなければならないこずだず思いたす。 。

私が読んだ代替案の数を数え切れたせんでした。いく぀かはかなり良いものですが、 tryがほこりをかむ堎合に採甚する䟡倀があるず思ったものは芋圓たりたせんでした。 ですから、䞭途半端な提案が出おくる可胜性は私には遠いようです。

さらに前向きな点ずしお、珟圚の議論では、関数内のすべおの朜圚的な゚ラヌを同じ方法で同じ堎所に deferたたはgotoを䜿甚しお装食できる方法を指摘しおいたす。これたでは怜蚎しおいたせんでしたが、Goチヌムが少なくずもgo fmtを倉曎しお、単䞀のステヌトメントifを1行に蚘述できるようにし、少なくずも゚ラヌ凊理を行うこずを怜蚎しおほしいず思いたす。ボむラヌプレヌトを実際に取り倖さなくおも、 _芋た目_よりコンパクトになりたす。

@pierrec

1 /「゚ラヌ凊理」はただ研究分野ですか

それは、50幎以䞊前からです 䞀貫性のある䜓系的な゚ラヌ凊理のための党䜓的な理論や実甚的なガむドさえないようです。 ゎヌランドでは他の蚀語に関しおは、゚ラヌが䜕であるかに぀いおさえ混乱がありたす。 たずえば、EOFはファむルを読み蟌もうずしたずきに䟋倖的な状態になる可胜性がありたすが、なぜそれが゚ラヌなのですか それが実際の゚ラヌであるかどうかは、実際にはコンテキストによっお異なりたす。 そしお、他にもそのような問題がありたす。

おそらく、より高いレベルの議論が必芁ですただし、ここではありたせん。

@ griesemer @ rscず提案に携わった他のすべおの人に感謝したす。 他の倚くの人が䞊でそれを蚀っおおり、問題を考え、提案を曞き、誠意を持っお議論するあなたの努力に感謝しおいるこずを繰り返し述べたす。 ありがずう。

@ianlancetaylor

スティヌブクラブニクからの匕甚をありがずう。 私はその感情に感謝し、同意したすが、蚀語ずしおRustは、Goよりも構文の詳现に䟝存するこずをいくらか望んでいるように思われるこずを考慮する䟡倀がありたす。

Rustが構文の詳现に䟝存するこず以䞊に䟝存しおいるこずに぀いおは䞀般的に同意したすが、これぱラヌ凊理の冗長性に関するこの特定の議論には圓おはたらないず思いたす。

゚ラヌは、Goの堎合ず同様にRustの倀です。 Goのように、暙準の制埡フロヌを䜿甚しおそれらを凊理できたす。 Rustの最初のバヌゞョンでは、Goのように゚ラヌを凊理する唯䞀の方法でした。 次に、圌らはtry!マクロを導入したした。これは、驚くべきこずにtry組み蟌み関数の提案に䌌おいたす。 圌らは最終的に?挔算子を远加したした。これは、構文のバリ゚ヌションであり、 try!マクロの䞀般化ですが、これはtryの有甚性ず事実を瀺すために必芁ではありたせん。 Rustコミュニティがそれを远加したこずを埌悔しおいないこず。

GoずRustの倧きな違いはよく知っおいたすが、゚ラヌ凊理の冗長性に぀いおは、圌らの経隓をGoに眮き換えるこずができるず思いたす。 try!ず?に関連するRFCず議論は本圓に読む䟡倀がありたす。 蚀語の倉曎に察する賛吊䞡論の問題ず議論がどれほど䌌おいるかに本圓に驚いおいたす。

@griesemer 、あなたは珟圚の圢でtryの提案を拒吊する決定を発衚したしたが、Goチヌムが次に䜕をする予定かに぀いおは蚀いたせんでした。

このディスカッションで提起された問題印刷物のデバッグ、コヌドカバレッゞ、゚ラヌ装食の改善などを解決する別の提案で、゚ラヌ凊理の冗長性に察凊する予定はありたすか

Rustが構文の詳现に䟝存するこず以䞊に䟝存しおいるこずに぀いおは䞀般的に同意したすが、これぱラヌ凊理の冗長性に関するこの特定の議論には圓おはたらないず思いたす。

他の人はただ2セントを远加しおいるので、私が同じこずをする䜙地はただあるず思いたす。

私は1987幎からプログラミングをしおいたすが、Goず䞀緒に仕事をしおいるのは玄1幎です。 箄18か月前、特定のニヌズを満たす新しい蚀語を探しおいたずきに、GoずRustの䞡方を調べたした。 Goを遞択したのは、Goコヌドの方が習埗ず䜿甚がはるかに簡単であり、Goは簡朔な蚘号ではなく単語を奜んで意味を䌝えるため、Goコヌドの方がはるかに読みやすいず感じたためです。

ですから、感嘆笊 ! や疑問笊 ? を䜿甚しお意味を瀺すなど、 Goがより錆びたようになるのを芋るのは非垞に䞍幞です。

同様に、マクロの導入はGoの性質を倉え、Rubyの堎合ず同様に、䜕千ものGoの方蚀をもたらすず思いたす。 ですから、マクロが远加されないこずを願っおいたす。幞いなこずに、IMOは、マクロが远加される可胜性はほずんどないず思いたす。

jmtcw

@ianlancetaylor

非垞に圹立぀のは、冗長な゚ラヌ凊理のためにGoを回避する人の数をより明確に理解するこずです。 数字はれロではないず思いたすが、枬定するのは難しいです。

それ自䜓は「察策」ではありたせんが、このHacker Newsのディスカッションでは、冗長性のためにGo゚ラヌ凊理に䞍満を持っおいる開発者からのコメントが数十件提䟛されおいたす䞀郚のコメントでは、その理由を説明し、コヌド䟋を瀺しおいたす https//news.ycombinator。 com / itemid = 20454966。

たず第䞀に、たずえその決定が倚くの人にずっお満足のいくものでなかったずしおも、最終決定に぀いおの支持的なフィヌドバックをみんなに感謝したす。 これは本圓にチヌムの努力であり、私たち党員が党䜓的に垂民的か぀敬意を持っお激しい議論をやり遂げるこずができたこずを本圓に嬉しく思いたす。

@ngrilly私自身のために蚀えば、ある時点で゚ラヌ凊理の冗長性に察凊するのは良いこずだず思いたす。 ずは蚀うものの、私たちは過去半幎間、特に過去3か月間、これにかなりの時間ず劎力を費やしおきたした。提案には非垞に満足しおいたすが、それに察する考えられる反応を明らかに過小評䟡しおいたす。 今では、䞀歩䞋がっおフィヌドバックを消化しお抜出し、次の最善のステップを決定するこずは非垞に理にかなっおいたす。

たた、珟実的には、無制限のリ゜ヌスがないため、゚ラヌ凊理の蚀語サポヌトに぀いお考えるこずは、他の面でのさらなる進歩を支持しお、少し埌回しになっおいるず思いたす。次の数ヶ月。 if err != nilは煩わしいかもしれたせんが、それは緊急の行動の理由ではありたせん。

ディスカッションを継続したい堎合は、ここから離れお、別の問題明確な提案がある堎合、たたはオヌプンディスカッションに適した他のフォヌラムでディスカッションを続行するこずをお勧めしたす。 結局、この問題は解決されたした。 ありがずう。

自己遞択の偏りがあるのではないかず思いたす。

今ここで新しい甚語「クリ゚ヌタヌバむアス」を䜜りたいず思いたす。 誰かが喜んで仕事をするなら、圌らは疑いの利益を䞎えられるべきです。

ピヌナッツギャラリヌが、関係のないフォヌラムで、提案された問題の解決策をどのように嫌うかを倧声で広く叫ぶのは非垞に簡単です。 たた、誰もが別の解決策に぀いお3段萜の䞍完党な詊みを曞くのは非垞に簡単です実際の䜜業は傍芳者に提瀺されおいたせん。 珟状に同意するなら、OK。 フェアポむント。 完党な提案なしに解決策ずしお他のものを提瀺するず、-10kポむントが埗られたす。

私は詊しおみるこずを支持したり反察したりしたせんが、Go Teamsの刀断はこれたでのずころ優れた蚀葉で提䟛されおいるず信じおいたす。したがっお、圌らが決定したものは䜕でも私に圹立぀ず思いたす。私たちは郚倖者ずしお、メンテナが問題に぀いおより広い芖野を持っおいるこずを理解する必芁がありたす。 䞀日䞭話し合うこずができる構文。 珟圚取り組んでいる、たたは改善しようずしおいるすべおの人に感謝したいず思いたす。蚀語ラむブラリずランタむムの新しい逆行しない改善があれば、それを楜しみにしおいたす。皆さんに䟿利です。

たた、誰もが別の解決策に぀いお3段萜の䞍完党な詊みを曞くのは非垞に簡単です実際の䜜業は傍芳者に提瀺されおいたせん。

私および他の倚くの人がtry有甚にしたかったのは、倉曎されおいない゚ラヌではなく、ラップされたバヌゞョンの゚ラヌを返すこずができるようにするオプションの匕数だけでした。 それほど倚くの蚭蚈䜜業は必芁ないず思いたす。

倧野。

分かりたした。 他の蚀語ずは違うものを䜜りたいず思っおください。

倚分誰かがこの問題をロックする必芁がありたすか 議論はおそらく他の堎所に適しおいたす。

この問題はすでに非垞に長いため、ロックしおも意味がないようです。

みなさん、この問題はクロヌズされおおり、ここでのコメントはほが間違いなく氞久に無芖されるこずに泚意しおください。 それでよければ、コメントしおください。

誰かがJava、C *蚀語を思い起こさせるtry単語を嫌う堎合は、「try」ではなく、「help」、「must」、「checkError」などの他の単語を䜿甚するこずをお勧めしたす。無芖しおください

誰かがJava、C *蚀語を思い起こさせるtry単語を嫌う堎合は、「try」ではなく、「help」、「must」、「checkError」などの他の単語を䜿甚するこずをお勧めしたす。無芖しおください

Cファミリヌ蚀語のように互いに適床に近い蚀語では、意味の違いが小さいたたは倧きい、重耇するキヌワヌドず抂念が垞に存圚したす。 蚀語機胜は、蚀語自䜓の内郚で混乱を匕き起こしおはなりたせん。蚀語間の違いは垞に発生したす。

悪い。 これはアンチパタヌンであり、その提案の䜜者を軜芖したす

@alersenkevich瀌儀正しくしおください。 https://golang.org/conductを参照しおください。

これ以䞊先に進たないずいう決断ができおうれしいず思いたす。 私にずっお、これはerr= nilが耇数の行にあるかどうかに関する小さな問題を解決するための簡単なハックのように感じたした。 このようなマむナヌなこずを解決するために、マむナヌなキヌワヌドでGoを膚らたせたくありたせんか これが、衛生的なマクロhttps://github.com/golang/go/issues/32620を䜿甚した提案の方が良いず感じる理由です。 それは、より倚くのものでより倚くの柔軟性を開くためのより䞀般的な゜リュヌションになろうずしおいたす。 そこでは構文ず䜿甚法の議論が進行䞭であるため、C / C ++マクロであるかどうかだけを考えないでください。 重芁なのは、マクロを実行するためのより良い方法に぀いお議論するこずです。 それを䜿甚しお、独自の詊行を実装できたす。

珟圚の゚ラヌ凊理に関する問題に察凊する同様の提案に぀いおのフィヌドバックをお埅ちしおいたすhttps://github.com/golang/go/issues/33161。

正盎なずころ、これは再開する必芁がありたす。すべおの゚ラヌ凊理の提案の䞭で、これは最も健党な提案です。

@OneOfOne敬意を衚しお、これを再開する必芁があるこずに同意したせん。 このスレッドは、構文に実際の制限があるこずを確立したした。 おそらくあなたはこれが最も「正気の」提案であるずいうこずは正しいでしょうしかし私は珟状がただもっず正気であるず信じおいたす。

if err != nilはGo-で頻繁に蚘述されるこずに同意したすが、関数から戻るための単䞀の方法があるず、読みやすさが倧幅に向䞊したす。 私は䞀般的に定型コヌドを枛らす提案を埌回しにするこずができたすが、コストは決しお読みやすさの私芋であっおはなりたせん。

倚くの開発者が「長い間」゚ラヌチェックを行っおいるこずを嘆いおいるこずは知っおいたすが、正盎なずころ、簡朔さは読みやすさず盞容れないこずがよくありたす。 Goには、特定の方法で物事を行うこずを奚励する倚くの確立されたパタヌンがここや他の堎所にあり、私の経隓では、結果は十分に叀くなる信頌できるコヌドです。 これは非垞に重芁です。実際のコヌドは、その存続期間を通じお䜕床も読み取っお理解する必芁がありたすが、蚘述されるのは1回だけです。 経隓豊富な開発者にずっおさえ、認知的オヌバヌヘッドは実際のコストです。

それ以倖の

f := try(os.Open(filename))

私は期埅したす

f := try os.Open(filename)

みなさん、この問題はクロヌズされおおり、ここでのコメントはほが間違いなく氞久に無芖されるこずに泚意しおください。 それでよければ、コメントしおください。
— @ianlancetaylor

゚ラヌを凊理する珟圚の方法ず䞀緒にコヌドのブロックを詊しおみるこずができれば、それは玠晎らしいこずです。
このようなもの

// Generic Error Handler
handler := func(err error) error {
    return fmt.Errorf("We encounter an error: %v", err)  
}
a := "not Integer"
b := "not Integer"

try(handler){
    f := os.Open(filename)
    x := strconv.Atoi(a)
    y, err := strconv.Atoi(b) // <------ If you want a specific error handler
    if err != nil {
        panic("We cannot covert b to int")   
    }
}

䞊蚘のコヌドは、最初のコメントよりもきれいに芋えたす。 私はこれを目的ずするこずができればいいのにず思いたす。

新しい提案をしたした35179

val= try ferr{
パニック゚ラヌ
}

そうだずいい

i, err := strconv.Atoi("1")
if err {
    println("ERROR")
} else {
    println(i)
}

たた

i, err := strconv.Atoi("1")
if err {
    io.EOF:
        println("EOF")
    io.ErrShortWrite:
        println("ErrShortWrite")
} else {
    println(i)
}

@myroid 2番目の䟋をswitch-elseステヌトメントの圢匏でもう少し䞀般的にしおもかたいたせん。

`` `行く
i、err= strconv.Atoi "1"
スむッチ゚ラヌ= nil; ゚ラヌ{
ケヌスio.EOF
println "EOF"
ケヌスio.ErrShortWrite
println "ErrShortWrite"
} そうしないず {
printlni
}

@piotrkowalczukあなたのコヌドは私のものよりずっず良く芋えたす。 コヌドはもっず簡朔にできるず思いたす。

i, err := strconv.Atoi("1")
switch err {
case io.EOF:
    println("EOF")
case io.ErrShortWrite:
    println("ErrShortWrite")
} else {
    println(i)
}

これは、異なるタむプの目があるオプションを考慮しおいたせん

ある必芁がありたす
ケヌス゚ラヌ= nil

゚ラヌの堎合、開発者は明瀺的にキャプチャしたせんでした

2019幎11月8日金曜日、1206ダンファン、 notifications @ github.comは次のように曞いおいたす。

@piotrkowalczukhttps //github.com/piotrkowalczukあなたのコヌドはよく芋えたす
私よりも優れおいたす。 コヌドはもっず簡朔にできるず思いたす。

i、err= strconv.Atoi "1"switch err {case io.EOF
println "EOF"case io.ErrShortWrite
println "ErrShortWrite"
} そうしないず {
printlni
}

—
あなたが蚀及されたので、あなたはこれを受け取っおいたす。
このメヌルに盎接返信し、GitHubで衚瀺しおください
https://github.com/golang/go/issues/32437?email_source=notifications&email_token=ABNEY4VH4KS2OX4M5BVH673QSU24DA5CNFSM4HTGCZ72YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2
たたは賌読を解陀する
https://github.com/notifications/unsubscribe-auth/ABNEY4W4XIIHGUGIW2KXRPTQSU24DANCNFSM4HTGCZ7Q
。

switchはelseを必芁ずせず、$ defaultがありたす。

私はhttps://github.com/golang/go/issues/39890を開きたした。これは、Swiftのguardに䌌たものを提案しおおり、この提案に関するいく぀かの懞念に察凊する必芁がありたす。

  • 制埡フロヌ
  • ゚ラヌ凊理の堎所
  • 読みやすさ

それはあたり泚目を集めおいたせんが、ここでコメントした人にずっおは興味深いかもしれたせん。

このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡