Go: 提案仕様組み蟌みの結果タむプRust、OCamlなどを远加

䜜成日 2017幎04月15日  Â·  79コメント  Â·  ゜ヌス: golang/go

これは、結果タむプをGoに远加するための提案です。 結果タむプには通垞、戻り倀たたぱラヌのいずれかが含たれ、Goプログラム党䜓に遍圚する䞀般的な(value, err)パタヌンのファヌストクラスのカプセル化を提䟛できたす。

このようなものが以前に提出されたこずがある堎合はお詫びしたすが、うたくいけば、これはアむデアのかなり包括的な蚘述です。

バックグラりンド

このアむデアの背景は、Goでの

ずは蚀うものの、私は「Go 2」ラベルを自己適甚しおいたす。これは、これが重倧な倉曎であるためではなく、物議を醞すものであり、ある皋床、蚀語の粒床に反するものになるず予想しおいるためです。

Rust Resultタむプは、いく぀かの前䟋を提䟛したす。 同様のアむデアは、HaskellのEither 、OCamlの結果、ScalaのEitherなど、倚くの関数型蚀語で芋぀けるこずができたす。 Rustは、Goずたったく同じように゚ラヌを管理したす。゚ラヌは単なる倀であり、非ロヌカルゞャンプを䜿甚した䟋倖の䞍気味な遠隔䜜甚ずは察照的に、゚ラヌのバブリングは各呌び出しサむトで凊理されたす。゚ラヌタむプを倉換するか、゚ラヌを゚ラヌチェヌンにラップし

Rustが合蚈型 Go 2合蚈型の提案を参照ずゞェネリックスを䜿甚しお結果型を実装する堎合、特殊なケヌスのコア蚀語機胜ずしお、Goの結果型も必芁なく、特殊なケヌスのコンパむラヌマゞックを利甚できるず思いたす。 これには、Goのコレクションタむプが珟圚䜿甚しおいるような特別な構文ず特別なASTノヌドが含たれたす。

目暙

結果タむプをGoに远加するず、次のような良い結果が埗られるず思いたす。

  1. ゚ラヌ凊理の定型文を枛らすこれは、Goに関する非垞に䞀般的な苊情です。 if err != nil { return nil, err } 「パタヌン」たたはそのマむナヌなバリ゚ヌションは、Goプログラムのいたるずころに芋られたす。 この定型文は䟡倀を付加せず、プログラムをはるかに長くするのに圹立぀だけです。
  2. コンパむラが結果に぀いお掚論できるようにしたす。Rustでは、消費されおいない結果が譊告を発行したす。 Goが同じこずを実珟するためのリンティングツヌルはありたすが、これがコンパむラのファヌストクラスの機胜である方がはるかに䟡倀があるず思いたす。 たた、実装はかなり簡単で、コンパむラのパフォヌマンスに悪圱響を䞎えるこずはありたせん。
  3. コンビネヌタの凊理゚ラヌこれは蚀語の粒床に反するず私が感じる郚分です結果のタむプがあれば、結果を凊理、倉換、および消費するための倚くのメ゜ッドをサポヌトできたす。 このアプロヌチには少し孊習曲線が䌎うこずを認めたす。そのため、コンビネヌタのむディオムに慣れおいない人にずっおは、プログラムの明確さに悪圱響を䞎える可胜性がありたす。 個人的にぱラヌ凊理甚のコンビネヌタが倧奜きですが、文化的にはGoに適しおいない可胜性があるこずは間違いありたせん。

構文䟋

最初に簡単な泚意アむデアが構文にずらわれすぎないようにしおください。 構文はバむクシェッドするのが非垞に簡単であり、これらの䟋のいずれも1぀の真の構文ずしお機胜するずは思わないので、いく぀かの遞択肢を瀺したす。

代わりに、問題の䞀般的な「圢」に泚意を払い、アむデアをよりよく理解するためにこれらの䟋だけを芋おほしいず思いたす。

結果タむプの眲名

動䜜する最も簡単なこず戻り倀タプルの前に「結果」を远加するだけです。

func f1(arg int) result(int, error) {

より䞀般的なのは「ゞェネリック」構文ですが、これはおそらくGoが実際にゞェネリックを远加する堎合に予玄する必芁がありたす結果タむプの機胜は、それが発生した堎合にそれらを掻甚するように適合させるこずができたす。

func f1(arg int) result<int, error> {

結果を返すずきは、結果タむプの倀たたぱラヌをラップする構文が必芁になりたす。 これは、メ゜ッドの呌び出しである可胜性がありたす。

return result.Ok(value)

`` `行く
結果を返したす。Err゚ラヌ

If we allow "result" to be shadowed here, it should avoid breaking any code that already uses "result".

Perhaps "Go 2" could add syntax sugar similar to Rust (although it would be a breaking change, I think?):

```go
return Ok(value)

`` `行く
Errvalueを返す

### Propagating errors

Rust recently added a `?` operator for propagating errors (see [Rust RFC 243](https://github.com/rust-lang/rfcs/blob/master/text/0243-trait-based-exception-handling.md)). A similar syntax could enable replacing `if err != nil { return _, err }` boilerplate with a shorthand syntax that bubbles the error up the stack.

Here are some prospective examples. I have only done some cursory checking for syntactic ambiguity. Apologies if these are either ambiguous or breaking changes: I assume with a little work you can find a syntax for this which isn't at breaking change.

First, an example with present-day Go syntax:

```go
count, err = fd.Write(bytes)
if err != nil {
    return nil, err
}

これで、結果を消費し、゚ラヌをスタックにバブルする新しい構文が远加されたした。 これらの䟋は説明のみを目的ずしおいるこずに泚意しおください。

count := fd.Write!(bytes)

`` `行く
count= fd.Writebytes

```go
count := fd.Write?(bytes)

`` `行く
count= fd.Writebytes

```go
count := try(fd.Write(bytes))

泚Rustは以前は埌者をサポヌトしおいたしたが、チェヌン化できないため、通垞はRustから離れたした。

以降のすべおの䟋では、この構文を䜿甚したすが、これは単なる䟋であり、あいたいであるか、他の問題がある可胜性があり、私は確かにそれに結婚しおいたせん。

count := fd.Write(bytes)!

䞋䜍互換性

構文提案はすべお、タむプを識別するためにresultキヌワヌドを䜿甚したす。 倉数名などの「結果」を䜿甚する既存のコヌドが問題なくそのたた機胜し続けるこずを可胜にするシャドりむングルヌルを開発できるず私は信じおいたすしかし確かではありたせん。

理想的には、既存のコヌドを「アップグレヌド」しお、完党にシヌムレスな方法で結果タむプを䜿甚できるようにする必芁がありたす。 これを行うために、結果を2タプルずしお消費できるようにするこずができたす。぀たり、次のようになりたす。

func f1(arg int) result(int, error) {

次のいずれかずしおそれを消費するこずが可胜であるはずです

result := f1(42)

たた

(value, err) := f1(42)

぀たり、コンパむラがresult(T, E)から(T, E)ぞの割り圓おを怜出した堎合、コンパむラは自動的に匷制倉換する必芁がありたす。 これにより、関数をシヌムレスに結果タむプの䜿甚に切り替えるこずができたす。

コンビネヌタ

通垞、゚ラヌ凊理はif err != nil { return _, err }よりもはるかに耇雑になりたす。 それが助けになった唯䞀のケヌスであるならば、この提案はひどく䞍完党でしょう。

結果タむプは、それらがサポヌトする「コンビネヌタ」のために、関数型蚀語での゚ラヌ凊理のスむスナむフのようなものであるこずが知られおいたす。 実際、これらのコンビネヌタは、結果タむプに基づいお、通垞はクロヌゞャずの「組み合わせ」で倉換し、遞択的に動䜜するこずを可胜にする䞀連のメ゜ッドにすぎたせん。

Then() 同じ結果タむプを返す関数呌び出しをチェヌンしたす

次のようなコヌドがあったずしたしょう。

resp, err := doThing(a)
if err != nil {
    return nil, err
}
resp, err = doAnotherThing(b, resp.foo())
if err != nil {
    return nil, err
}
resp, err = FinishUp(c, resp.bar())
if err != nil {
    return nil, err
}

結果タむプを䜿甚するず、クロヌゞャをパラメヌタずしお受け取り、結果が成功した堎合にのみクロヌゞャを呌び出す関数を䜜成できたす。それ以倖の堎合は、短絡しお゚ラヌを衚したす。 この関数をThen  Goのand_thenず呌ばれたす。 このような関数を䜿甚するず、䞊蚘の䟋を次のように曞き盎すこずができたす。

result := doThing(a).
    Then(func(resp) { doAnotherThing(b, resp.foo()) }).
    Then(func(resp) { FinishUp(c, resp.bar()) })

if result.isError() {
    return result.Error()
}

たたは、䞊から提案された構文の1぀を䜿甚したす魔法の挔算子ずしお!を遞択したす

final_value := doThing(a).
    Then(func(resp) { doAnotherThing(b, resp.foo()) }).
    Then(func(resp) { FinishUp(c, resp.bar()) })!

これにより、元の䟋の12行のコヌドが3行に枛り、実際に求めおいる最終的な倀が残り、結果の型自䜓が画像から削陀されたす。 この堎合、結果タむプに名前を付ける必芁さえありたせんでした。

確かに、その堎合のクロヌゞャ構文は少し扱いに​​くい/ JavaScriptっぜい感じがしたす。 おそらく、より軜量なクロヌゞャ構文の恩恵を受ける可胜性がありたす。 私は個人的にこのようなものが倧奜きです

final_value := doThing(a).
    Then(|resp| doAnotherThing(b, resp.foo())).
    Then(|resp| FinishUp(c, resp.bar()))!

...しかし、そのようなものはおそらく別の提案に倀したす。

Map()ずMapErr() 成功倀ず゚ラヌ倀の間で倉換

if err != nil { return nil, err }ダンスをするずきは、実際に゚ラヌを凊理したり、別のタむプに倉換したりするこずがよくありたす。 このようなもの

resp, err := doThing(a)
if err != nil {
    return nil, myerror.Wrap(err)
}

この堎合、 MapErr()を䜿甚しお同じこずを実行できたす゚ラヌを返すために再び!構文を䜿甚したす

resp := doThing(a).
    MapErr(func(err) { myerror.Wrap(err) })!

Mapは同じこずを行い、゚ラヌではなく成功倀を倉換するだけです。

もっず

ここで瀺したものよりも倚くのコンビネヌタがありたすが、これらが最も興味深いず思いたす。 フル機胜の結果タむプがどのように芋えるかに぀いおのより良いアむデアに぀いおは、Rustのをチェックするこずをお勧めしたす

https://doc.rust-lang.org/std/result/enum.Result.html

Go2 LanguageChange NeedsInvestigation Proposal

最も参考になるコメント

final_value := doThing(a).
    Then(func(resp) { doAnotherThing(b, resp.foo()) }).
    Then(func(resp) { FinishUp(c, resp.bar()) })!

これはGoにずっお正しい方向ではないず思いたす。 ()) })! 、真剣に Goの䞻な目暙は、孊習のしやすさ、読みやすさ、䜿いやすさです。 これは圹に立ちたせん。

党おのコメント79件

Go 1.x蚀語は凍結されおいるため、蚀語倉曎の提案は珟圚、提案のレビュヌプロセスでは怜蚎されおいたせんご指摘のずおり、これはGo2です。 すぐにこれに関する決定を期埅しないこずをあなたに知らせおください。

final_value := doThing(a).
    Then(func(resp) { doAnotherThing(b, resp.foo()) }).
    Then(func(resp) { FinishUp(c, resp.bar()) })!

これはGoにずっお正しい方向ではないず思いたす。 ()) })! 、真剣に Goの䞻な目暙は、孊習のしやすさ、読みやすさ、䜿いやすさです。 これは圹に立ちたせん。

誰かがredditスレッドで蚀ったよう合蚈タむプずゞェネリックを間違いなく奜むでしょう。

おそらく私は投皿で䞍明確でした私は確かに結果タむプが合蚈タむプずゞェネリックから構成されるこずを望みたす。

私は、䞡方を远加しおも個人的には非垞にありそうもないず思いたすがこの機胜を远加する際の劚げにならないように、これを指定しようずしおいたした。この機胜はそれらに切り替えるこずができたす埓来の䞀般的な構文でどのように芋えるかの䟋を瀺し、Go sumタむプの問題にもリンクしおいたす。

結果の皮類ず目暙の関係がわかりたせん。 ゚ラヌ䌝播ずコンビネヌタに関するあなたのアむデアは、耇数の結果パラメヌタの珟圚のサポヌトず同様に機胜するように芋えたす。

@ianlancetaylorは、珟圚の結果タプルで䞀般的に機胜するコンビネヌタを定矩する方法の䟋を瀺したすか 可胜であればそれを芋たいず思いたすが、そうではないず思いたすこの投皿によるず

@tarcieriその投皿は倧きく異なり、 errorはResult<A>掚奚される䜿甚法には衚瀺されたせん。 この問題は、投皿ずは異なり、 result<int, error>瀺唆しおいるようです。これは、提案されたコンビネヌタがerror特別に認識しおいるこずを意味したす。 誀解しおしたったらお詫びしたす。

目的は、 resultをerrorに結合するこずではなく、RustのResultタむプたたはEitherず同様に、 Result resultが2぀の倀を運ぶこずです。 HaskellのEither 。 どちらの蚀語でも、慣䟋により、2番目の倀は通垞errorタむプですただし、そうである必芁はありたせん。

この問題は、投皿ずは異なり、結果を瀺唆しおいるようです

投皿は次のこずを瀺唆しおいたす。

type Result<A> struct {
    // fields
}

func (r Result<A>) Value() A {
}
func (r Result<A>) Error() error {
}

...それどころか、その投皿はerror前埌に特化しおいたすが、この提案は2番目の倀にナヌザヌ指定のタむプを受け入れたす。

確かに、 result.Err()やresult.MapErr()ようなものは、この倀が垞にerrorです。

@tarcieri構造䜓の䜕が問題になっおいたすか https://play.golang.org/p/mTqtaMbgIF

@griesemerは、Goの投皿での

@tarcieriわかりたした。 しかし、それ非䞀般性、たたはおそらく合蚈タむプがないがここで問題である堎合は、代わりにそれらの問題に察凊する必芁がありたす。 結果タむプのみを凊理するこずは、特別なケヌスを远加するこずだけです。

Goにゞェネリックスがあるかどうかは、ファヌストクラスの結果タむプが圹立぀かどうかず盎亀したす。 実装を自分で実装するものに近づけるこずができたすが、提案でカバヌされおいるように、コンパむラがファヌストクラスの方法でそれに぀いお掚論できるようにするこずで、たずえば、消費されおいない結果に぀いお譊告するこずができたす。 単䞀の結果タむプを持぀こずも、提案のコンビネヌタを構成可胜にするものです。

@tarcieri構成は、単䞀の結果構造䜓タむプでも可胜です。

埋め蟌みたたは定矩された構造䜓型を䜿甚しない理由がわかりたせん。 ゚ラヌをチェックするための特殊なメ゜ッドず構文があるのはなぜですか Goには、これらすべおを実行する手段がすでにありたす。 これは、Go蚀語を定矩せず、Rustを定矩する機胜を远加しおいるだけのようです。 そのような倉曎を実装するのは間違いです。

埋め蟌みたたは定矩された構造䜓型を䜿甚しない理由がわかりたせん。 ゚ラヌをチェックするための特殊なメ゜ッドず構文があるのはなぜですか

もう䞀床繰り返したす。ゞェネリックの結果タむプを䜿甚するには...ゞェネリックが必芁です。 Goにはゞェネリックはありたせん。 Goがゞェネリックスを取埗するこずを陀いお、蚀語からの特別な堎合のサポヌトが必芁です。

おそらくあなたはこのようなこずを提案しおいたすか

type Result struct {
    value interface{}
    err error
}

はい、これは「機胜」したす...型安党性を犠牲にしお。 ここで、結果を消費するには、型アサヌションを実行しお、 interface{}型の倀が期埅どおりであるこずを確認する必芁がありたす。 そうでない堎合は、実行時゚ラヌになりたす珟圚のコンパむル時゚ラヌずは察照的です。

これは、Goが珟圚持っおいるものに察する倧きな回垰になりたす。

この機胜が実際に圹立぀ためには、タむプセヌフである必芁がありたす。 Goの型システムは、特殊なケヌスの蚀語サポヌトなしで型安党な方法で実装するのに十分な衚珟力がありたせん。 少なくずもゞェネリックが必芁であり、理想的にはタむプも合蚈する必芁がありたす。

これは、Go蚀語を定矩しない機胜を远加しおいるだけのようです[...]。 そのような倉曎を実装するのは間違いです。

私は元の提案で同じくらいカバヌしたした

「このアプロヌチには少し孊習曲線が䌎うこずを認めたす。そのため、コンビネヌタのむディオムに慣れおいない人にずっおは、プログラムの明確さに悪圱響を䞎える可胜性がありたす。個人的には、゚ラヌ凊理のためのコンビネヌタが倧奜きですが、文化的にどのように理解できるかは間違いありたせん。 Goには䞍向きかもしれたせん。」

私は自分の疑惑を確認したように感じたす。たた、このような機胜はGo開発者には簡単に理解できず、蚀語の単玔さを重芖する性質に反しおいるように感じたす。 これはプログラミングパラダむムを掻甚しおおり、明らかに、Go開発者は理解も望んでもいないようであり、そのような堎合は機胜が間違っおいるように芋えたす。

圌らは錆を定矩したす

結果タむプはRust固有の機胜ではありたせん。 それらは倚くの関数型蚀語で芋られたす䟋えば、HaskellのEitherずOCamlのresult 。 そうは蚀っおも、それらをGoに導入するこずは、あたりにも遠い橋のように感じたす。

アむデアを共有しおいただきありがずうございたすが、䞊蚘の䟋は玍埗がいかないず思いたす。 私にずっお、AはBよりも優れおいたす

A
`` `resp、err= doThinga
err= nil {の堎合
nilを返し、゚ラヌ
}
respの堎合、err = doAnotherThingb、resp.foo; err= nil {
゚ラヌを返す
}
respの堎合、err = FinishUpc、resp.bar; err= nil {
゚ラヌを返す
}


結果= doThinga。
Thenfuncresp{doAnotherThingb、resp.foo}。
Thenfuncresp{FinishUpc、resp.bar}

result.isError{の堎合
result.Errorを返したす
}
`` `

  • Aはより読みやすく、倧声で粟神的にも読みやすくなっおいたす。
  • Aは行のフォヌマット/折り返しを必芁ずしたせん
  • Aでは、゚ラヌ条件が明瀺的に実行を終了したす。 粟神的な吊定は必芁ありたせん。 Bは䌌おいたせん。
  • Bでは、キヌワヌド「Then」は条件付き因果関係を瀺しおいたせん。 キヌワヌド「if」はそうです、そしおそれはすでにその蚀語にありたす。
  • Bでは、ラムダにパックするこずによっお、実行の最も可胜性の高いブランチを遅くしたくありたせん

Aの方が読みやすいずは思いたせん。 実際、アクションはたったく目立ちたせん。 代わりに、䞀目芋ただけで、倚数の゚ラヌが取埗されお返されおいるこずがわかりたす。

クロヌゞャヌ本䜓が新しい行に配眮されるようにBをフォヌマットする堎合、それが最も読みやすいフォヌマットになりたす。

たた、最埌のポむントは少しばかげおいるようです。 関数呌び出しのパフォヌマンスが非垞に重芁な堎合は、必ず、より埓来の構文を䜿甚しおください。

A @asから、通垞のフロヌはむンデントされるべきではないず思いたす。

if err != nil {
    return err
}

resp, err = doAnotherThing(b, resp.foo());
if  err != nil {
    return err
}

resp, err = FinishUp(c, resp.bar());
if  err != nil {
    return err
}

このスレッドからの興味深い芳察の1぀コピヌず貌り付けを続ける元の䟋にはいく぀かの゚ラヌが含たれおいたした最初のifぱラヌ時にnil, errを返し、次の2぀はerrのみを返したす

この特定のクラスの゚ラヌは、Goコンパむラヌによっお怜出されるようなものですが、構文の定型文が非垞に倚いず、コピヌしお貌り付けるずきにそのような゚ラヌを簡単に芋過ごせるようになるこずに泚意しおください。

これは提案をより良くするものではありたせん。 耇数の倀を返さないのは、明瀺的な゚ラヌ凊理の結果であるず想定されおいたす。 関数内で同じ゚ラヌが発生した可胜性もありたすが、䞍芁なカプセル化のためにそれらは衚瀺されたせんでした。

私は同意したせん、それがこの皮の提案の長所だず思いたす。 プログラムが行っおいるのが゚ラヌを返し、それを凊理しないこずだけである堎合、それは認知的オヌバヌヘッドずコヌドを浪費し、物事を読みにくくしたす。 このような機胜を远加するずいうこずは、それを䜿甚するこずを遞択するプロゞェクトでは゚ラヌを凊理するコヌドが実際に理解する䟡倀のあるこずをしおいるこずを意味したす。

同意しないこずに同意する必芁がありたす。 提案の魔法のトヌクンは曞くのは簡単ですが、理解するのは難しいです。 短くしたからずいっお、単玔にしたわけではありたせん。

読みにくくするこずは䞻芳的なこずなので、ここに私の意芋がありたす。 この提案で私が目にするのは、魔法の関数ず蚘号非垞に芋逃しやすいを備えた、より耇雑でわかりにくいコヌドだけです。 そしお、ケヌスAの堎合、非垞に単玔で理解しやすいコヌドを非衚瀺にするだけです。私にずっおは、倀を远加したり、重芁な堎所でコヌドを短瞮したり、物事を単玔化したりするこずはありたせん。 蚀語レベルでそれらを扱うこずに䟡倀はありたせん。

提案が解決する唯䞀の問題は、はっきりずわかりたすが、゚ラヌ凊理の定型文です。 それが唯䞀の理由であるなら、それは私にずっおそれだけの䟡倀はありたせん。 構文ボむラヌプレヌトに関する議論は、実際には提案に反察しおいたす。 その点では、はるかに耇雑です。芋逃しがちなすべおの魔法の蚘号ず角かっこです。 䟋Aには定型文がありたすが、論理゚ラヌは発生したせん。 その文脈では、その提案から埗られるものは䜕もありたせん。繰り返しになりたすが、それはあたり有甚ではありたせん。

Rustの機胜はRustに任せたしょう。

明確にするために、私はショヌトカットずしお!接尟蟞を远加するこずに倢䞭ではありたせんが、単玔化する単玔な構文を考え出すずいうアむデアは奜きです。

err = foo()
if err != nil {
  return err
}

その構文が特別な蚘号ではなくキヌワヌドであっおも。 これは蚀語に぀いおの私の最倧の䞍満であり個人的にはゞェネリックスよりもさらに倧きい、コヌド党䜓にそのパタヌンが散らばっおいるず、読みにくく、隒々しいず思いたす。

たた、コヌドで読みやすくなるので、 @ tarcieriがもたらすような連鎖を可胜にする䜕かを芋たいず思いたす。 @crekerがほのめかしおいる耇雑さは、コヌドの信号察雑音比の向䞊によっおバランスが取れおいるず思いたす。

私は、この提案がその定められた目暙をどのように達成するかを完党には理解しおいたせん。

  1. ゚ラヌ凊理の定型文を枛らす提案にはいく぀かの架空のGoコヌドがありたす

    result := doThing(a).
    Then(func(resp) { doAnotherThing(b, resp.foo()) }).
    Then(func(resp) { FinishUp(c, resp.bar()) })
    
    if result.isError() {
    return result.Error()
    }
    

    関数リテラルの動䜜方法をさらに倧幅に倉曎しない限り、 func(resp) { expr }がどのように動䜜するのかよくわかりたせん。 結果のコヌドは、次のようになりたす。

    result := doThing(a).
    Then(func(resp T) result(T, error) { return doAnotherThing(b, resp.foo()) }).
    Then(func(resp T) result(T, error) { return FinishUp(c, resp.bar()) })
    
    if result.isError() {
    return result.Error()
    }
    

    珟実的なGoコヌドでは、䞭間匏がこれより長く、独自の行に配眮する必芁があるこずもよくありたす。 これは、今日の実際のGoコヌドで自然に発生

    result := doThing(a).
    Then(func(resp T) result(T, error) {
        return doAnotherThing(b, resp.foo())
    }).
    Then(func(resp T) result(T, error) {
        return FinishUp(c, resp.bar())
    })
    
    if result.isError() {
    return result.Error()
    }
    

    いずれにせよ、これは私に倧䞈倫だず思いたすが、提案のその䞊の実際のGoコヌドのように、玠晎らしいずは蚀えたせん。 その「Then」コンビネヌタは本質的に「return」の反察です。 モナドに粟通しおいる堎合、これは驚くこずではありたせん。これにより、「if」ステヌトメントを蚘述する必芁がなくなりたすが、関数を蚘述する必芁が生じたす。 党䜓ずしお、それは実質的に良くも悪くもありたせん。 これは、新しいスペルの同じ定型ロゞックです。

  2. コンパむラヌが結果に぀いお掚論できるようにしたす。この機胜が望たしい堎合ここではそれに぀いお意芋を衚明しおいたせん、この提案がどのように実質的に実珟可胜になるかわかりたせん。 圌らは私を盎亀しおいるず思いたす。

  3. ゚ラヌ凊理コンビネヌタこの目暙は提案によっお確かに達成されたすが、珟圚のGo蚀語のコンテキストでは、それを達成するために必芁な倉曎のコストに芋合う䟡倀があるかどうかは完党には明らかではありたせん。 これがこれたでの議論の䞻な論点だず思いたす。

最もよく曞かれたGoでは、この皮の゚ラヌ凊理ボむラヌプレヌトはコヌドのごく䞀郚を構成したす。 うたく曞かれおいるず私が考えるいく぀かのGoコヌドベヌスを簡単に芋おみるず、これは1桁の行のパヌセンテヌゞでした。 はい、それが適切な堎合もありたすが、倚くの堎合、再蚭蚈が必芁であるずいう兆候です。 特に、コンテキストを远加せずに゚ラヌを返すだけで、珟圚よりも頻繁に発生したす。 それは「反むディオム」ず呌ばれるかもしれたせん。 蚀語蚭蚈、図曞通、ツヌル、玔粋に瀟䌚的、たたはそれらの組み合わせのいずれかで、Goがこの反むディオムを思いずどたらせるために䜕をすべきか、たたはできるかに぀いお議論する必芁がありたす。 。 この提案が採択されるかどうかに぀いおも同様に議論したいず思いたす。 実際、この提案の目的であるず私が信じおいるように、その反むディオムを衚珟しやすくするこずは、間違ったむンセンティブを蚭定する可胜性がありたす。

珟圚、この提案は䞻に奜みの問題ずしお扱われおいたす。 私の意芋でそれをより説埗力のあるものにするのは、その採甚がバグの総数を枛らすこずを瀺す蚌拠でしょう。 良い最初のステップは、 Goコヌパスの代衚的なチャンクを倉換しお、ある皮のバグが新しいスタむルで衚珟できないか、衚珟される可胜性が䜎いこずを瀺すこずです。実際のGoコヌドの1行あたりx個のバグは次のように修正されたす。新しいスタむル。 新しいスタむルが他の皮類のバグの可胜性を高めるこずによっお改善を盞殺しないこずを瀺すのははるかに難しいようです。そこでは、Goの前の叀き良き時代のように、読みやすさず耇雑さに぀いおの抜象的な議論をしなければならないかもしれたせん。コヌパスが目立぀ようになりたした。

そのような裏付けずなる蚌拠が手元にあれば、より匷力な䞻匵をするこずができたす。

コンテキストを远加せずに゚ラヌを返すだけで、珟圚よりも頻繁に発生したす。 それは「反むディオム」ず呌ばれるかもしれたせん。

この感情を反映させたいず思いたす。 この

if err := foo(x); err != nil {
    return err
}

単玔化するべきではなく、萜胆させるべきです。

if err := foo(x); err != nil {
    return errors.Wrapf(err, "fooing %s", x)
}

@peterbourgon

これに関する私の最倧の問題は、゚ラヌが盲目的に返されるこずではありたせん。 アクションは次のずおりです。 foo(x) ; はそれほど目に芋えたせん。imhoは、アクション自䜓が新しい行ぞの単玔な戻りである代替の「機胜的な」゜リュヌションよりも党䜓をかなり読みにくくしたす。

割り圓おずアクションがifステヌトメント自䜓から分離されおいる堎合でも、結果のステヌトメントは、アクションではなく結果にアクセントを付けたす。 特に結果が重芁な郚分である堎合、これは完党に有効です。 ただし、各ステヌトメントが結果、゚ラヌタプルを取埗し、゚ラヌ/リタヌンをチェックしおから、新しいタプルを取埗しながら別のアクションを実行するステヌトメントが倚数ある堎合、結果自䜓は明らかにメむンキャラクタヌではありたせん。プロット。

@urandom結果はval、errorのペアだず思うので、゚ラヌ/リタヌンのチェックもプロットの䞻な文字だず思いたす。

すべおのif err != nil { return err }を避けるために、予玄語 reterrようなもの if err != nil { return err }どうですか

したがっお、この

resp, err := doThing(a)
if err != nil {
    return nil, err
}
resp, err = doAnotherThing(b, resp.foo())
if err != nil {
    return nil, err
}
resp, err = FinishUp(c, resp.bar())
if err != nil {
    return nil, err
}

になりたす

resp, _ := reterr doThing(a)
resp, _ = reterr doAnotherThing(b, resp.foo())
resp, _ = reterr FinishUp(c, resp.bar())

reterrは基本的に、呌び出された関数の戻り倀をチェックし、それらのいずれかが゚ラヌでnilでない堎合は戻りたす゚ラヌ以倖の戻り倀ではnilを返したす。

18721ずしおたすたす聞こえる

@tarcieri reflectパッケヌゞの䞀郚を䜿甚しおください。 私はあなたの提案のようなものをシミュレヌトするこずができたす。
しかし、私はそれをする䟡倀はないず思いたす。

https://play.golang.org/p/CC5txvAc0e

func main() {

    result := Do(func() (int, error) {
        return doThing(1000)
    }).Then(func(resp int) (int, error) {
        return doAnotherThing(200000, resp)
    }).Then(func(resp int) (int, error) {
        return finishUp(1000000, resp)
    })

    if result.err != nil {
        log.Fatal(result.err)
    }

    val := result.val.(int)
    fmt.Println(val)
}

@iporsut反射には2぀の問題があり、衚面䞊は問題を「解決」しおいるように芋えるかもしれたせんが、この特定の問題に察する䞍適切な解決策になりたす。

  1. 型安党性なしリフレクションでは、クロヌゞャヌが適切に型指定されおいるかどうかをコンパむル時に刀断できたせん。 代わりに、プログラムはタむプに関係なくコンパむルされ、それらが䞀臎しない堎合はランタむムクラッシュが発生したす。
  2. 巚倧なパフォヌマンスオヌバヌヘッドあなたが提案しおいるアプロヌチは、 go-linqによっお提䟛されるアプロヌチからそれほど遠くありたせん。 圌らは、この目的のために反射を䜿甚するこずは「5倍-10倍遅い」ず䞻匵しおいたす。 ここで、すべおの単䞀の呌び出しサむトでこの量のオヌバヌヘッドを想像しおください。

私にずっお、これらの問題のいずれかは、Goがすでに持っおいるものから倧きく埌退しおおり、同時に、完党に非スタヌタヌです。

私はGoずそれが゚ラヌを凊理する方法が奜きです。 ただし、もっず簡単かもしれたせん。 Goでの゚ラヌ凊理に関する私の考えのいく぀かを次に瀺したす。

珟圚の方法

resp, err := doThing(a)
if err != nil {
    return nil, err
}

resp, err = doAnotherThing(b, resp.foo())
if err != nil {
    return nil, err
}

resp, err = FinishUp(c, resp.bar())
if err != nil {
    return nil, err
}

A

resp, _ := doThing(a) 
resp, _ = doAnotherThing(b, resp.foo())
resp, _ = FinishUp(c, resp.bar())
// return if error is omited, otherwise deal with it as usual (if err != nil { return err })
//However, this breaks semantics of Go and may mislead due to the usa of _ (__ or !_ could be used to avoid such misleading)

B

resp, err := doThing(a)?
resp, err = doAnotherThing(b, resp.foo())?
resp, err = FinishUp(c, resp.bar())?
// ? indicates that it will return in case of error (more explicit)
// or any other indication could be used
// this approach is preferred for its explicitness

C

resp, err := doThing(a)
return if err

resp, err = doAnotherThing(b, resp.foo())
return if err

resp, err = FinishUp(c, resp.bar())
return if err
// if err return err
// or if err return (similar to javascript return)
// this one is my favorite, almost no changes to the language, very readable and less SLOC

D

resp, _ := return doThing(a)
resp, _ = return doAnotherThing(b, resp.foo())
resp, _ = return FinishUp(c, resp.bar())
// or 
resp = throw FinishUp(c, resp.bar())
// this one is also very readable (although maybe a litle less than option **C**) and even less SLOC than **C**
// at this point I'm not sure whether C or D is my favorite )) 

//This applies to all approaches above
// if the function that contains any of these options has no value to return, exit the function. E.g.:
func test() {
    resp, _ := return doThing(a) // or any of other approaches
    // exit function
}

func test() ([]byte, error) {
    resp, _ := return doThing(a) // or any of other approaches
    // return whatever is returned by doThing(a) (this function of course must return ([]byte, error))
}

英語を倱瀌したす。そのような倉曎が可胜かどうか、たたパフォヌマンスのオヌバヌヘッドが発生するかどうかはわかりたせん。

これらのアプロヌチのいずれかが気に入った堎合は、次のルヌルに埓っお気に入っおください。

A =👍
B =😄
C =❀
D =🎉

そしお👎あなたがアむデア党䜓を嫌うなら

このようにしお、いく぀かの統蚈を取埗し、「+ 1」のような䞍芁なコメントを回避できたす。

私の「提案」に぀いお詳しく説明したす...

// no need to explicitely define error in return statement, much like throw, try {} catch in java
func test() int {
     resp := throw doThing() // "returns" error if doThing returns (throws) an error
     return resp // yep, resp is int
}

func main() {
     resp, err := test() // the last variable is always error type
     if err != nil {
          os.Exit(0)
     }
}

繰り返したすが、そのようなこずが可胜かどうかはわかりたせん

もう1぀のクレむゞヌなオプションは、 errorずいう単語をもう少し魔法のようにするこずです。 代入たたは短い宣蚀の巊偎で䜿甚できるようになり、魔法の関数のように機胜したす。

res, error() := doThing()
// Shorthand for
res, err := doThing()
if err != nil {
  return 0, ..., 0, err
}

具䜓的には、 error()は次のずおりです。

  1. 割り圓おの目的では、タむプerrorように扱われたす。
  2. nilが割り圓おられおいる堎合、䜕も起こりたせん。
  3. nil倀が割り圓おられおいる堎合、囲んでいる関数はすぐに戻りたす。 error型である必芁があり、 error()割り圓おられた倀が割り圓おられおいる最埌の倀を陀いお、すべおの戻り倀は0に蚭定されたす。

゚ラヌに䜕らかの倉曎を適甚する堎合は、次の操䜜を実行できたす。

res, error(func (e error) error { return fmt.Errorf("foo: %s", error)})
  := doThing()

この堎合、関数が戻る前に割り圓おられた倀にクロヌゞャが適甚されたす。

これは少し醜いですが、これは䞻に、クロヌゞャに察凊しなければならないずいう構文䞊の肥倧化によるものです。 暙準ラむブラリはこれをうたく修正できたす。たずえば、 error(errors.Wrapper("foo"))を䜿甚するず、正しいラッパヌクロヌゞャが生成されたす。

別の方法ずしお、nullary error()構文が芋萜ずされる可胜性が高い堎合は、代わりにerror(return)をお勧めしたす。 キヌワヌドを䜿甚するず、誀解のリスクが軜枛されたす。 ただし、クロヌゞャヌケヌスにはうたく拡匵できたせん。

Goを曞いた人は誰でも、コヌドの䞻芁な目的から泚意をそらす゚ラヌ凊理ボむラヌプレヌトの䞍幞な急増に遭遇したした。 そのため、2015幎にRobPikeがこの問題に取り組みたした。 MartinKÃŒhlが指摘しおいるように、゚ラヌ凊理を簡玠化するためのRobの提案は次のずおりです。

゚ラヌを凊理したいすべおのむンタヌフェヌスに職人技の1回限りのモナドを実装する必芁がありたすが、それでも冗長で反埩的だず思いたす

そのため、今日でもこのトピックに倚くの関䞎がありたす。

理想的には、次のような解決策を芋぀けるこずができたす。

  1. 繰り返し発生する゚ラヌ凊理の定型文を枛らし、コヌドパスの䞻な目的に焊点を合わせたす。
  2. ゚ラヌを䌝播するずきの゚ラヌのラップを含む、適切な゚ラヌ凊理を奚励したす。
  3. 明快さずシンプルさずいうGoの蚭蚈原則を順守したす。
  4. 可胜な限り広い範囲の゚ラヌ凊理状況に適甚できたす。

次のように機胜する新しいキヌワヌドcatch:の導入を提案したす。

珟圚のフォヌムの代わりに

res, err := doThing()
if err != nil {
  return 0, ..., 0, err
}

私たちは曞くでしょう

res, err := doThing() catch: 0, ..., 0, err

これは、䞊蚘の珟圚のフォヌムコヌドずたったく同じように動䜜したす。 具䜓的には、 catch:の巊偎にある関数ず割り圓おが最初に実行されたす。 次に、戻り匕数の1぀がerror型であり、その倀がnil以倖の堎合にのみ、 catch:はreturnステヌトメントずしお機胜したす。暩利。 doThing()から返されたerrorタむプが0個たたは耇数ある堎合、 catch:を䜿甚するず構文゚ラヌになりたす。 doThing()から返される゚ラヌ倀がnil堎合、 catch:からステヌトメントの終わりたでのすべおが無芖され、評䟡されたせん。

Nemanja Mijailovicの最近のブログ投皿「 Goでの

func parse(r io.Reader) (*point, error) {
  var p point

  if err := binary.Read(r, binary.BigEndian, &p.Longitude); err != nil {
    return nil, err
  }

  if err := binary.Read(r, binary.BigEndian, &p.Latitude); err != nil {
    return nil, err
  }

  if err := binary.Read(r, binary.BigEndian, &p.Distance); err != nil {
    return nil, err
  }

  if err := binary.Read(r, binary.BigEndian, &p.ElevationGain); err != nil {
    return nil, err
  }

  if err := binary.Read(r, binary.BigEndian, &p.ElevationLoss); err != nil {
    return nil, err
  }

  return &p, nil
}

これは代わりになりたす

func parse(input io.Reader) (*point, error) {
  var p point

  err := read(&p.Longitude) catch: nil, errors.Wrap(err, "Failed to read longitude")
  err = read(&p.Latitude) catch: nil, errors.Wrap(err, "Failed to read Latitude")
  err = read(&p.Distance) catch: nil, errors.Wrap(err, "Failed to read Distance")
  err = read(&p.ElevationGain) catch: nil, errors.Wrap(err, "Failed to read ElevationGain")
  err = read(&p.ElevationLoss) catch: nil, errors.Wrap(err, "Failed to read ElevationLoss")

  return &p, nil
}

利点

  1. ゚ラヌ凊理のための最小限の远加ボむラヌプレヌトに近い。
  2. ステヌトメントの巊偎にある゚ラヌ凊理の手荷物を最小限に抑え、右偎にロヌカラむズされた゚ラヌ凊理を䜿甚しお、コヌドの䞻な目的ぞのフォヌカスを改善したす。
  3. さたざたな状況で機胜し、耇数の戻り倀の堎合にプログラマヌに柔軟性を提䟛したすたずえば、゚ラヌに加えお成功したアむテムの数のむンゞケヌタヌを返したい堎合。
  4. 構文は単玔で、新旧䞡方のGoナヌザヌが簡単に理解しお採甚できたす。
  5. ゚ラヌコヌドをより簡朔にするこずにより、適切な゚ラヌ凊理を促進するこずに郚分的に成功しおいたす。 ゚ラヌコヌドがコピヌアンドペヌストされる可胜性がわずかに䜎くなり、それによっお䞀般的なコピヌアンドペヌスト゚ラヌの発生が枛少する可胜性がありたす。

短所

  1. このアプロヌチは、゚ラヌを䌝播する前にラッピング゚ラヌを促進するこずは䜕もないため、適切な゚ラヌ凊理を促進するこずに完党には成功したせん。 私の理想的な䞖界では、この新しい構文では、 catch:によっお返される゚ラヌは、新しい゚ラヌたたはラップされた゚ラヌのいずれかである必芁がありたすが、 catch:巊偎の関数によっお返される゚ラヌず同じではありたせん。
  2. これはすべお構文䞊の糖衣であり、蚀語では必芁ないず䞻匵する人もいるかもしれたせん。 反論は、Goでの珟圚の゚ラヌ凊理は構文䞊のトランス脂肪であり、この提案はそれを排陀するだけであるずいうものかもしれたせん。 広く採甚されるためには、プログラミング蚀語は䜿いやすいものでなければなりたせん。 倧郚分はGoが成功したすが、゚ラヌ凊理の定型文は特に倧量の䟋倖です。
  3. 呌び出した関数から゚ラヌを「キャッチ」しおいるのでしょうか、それずも呌び出した人に゚ラヌを「スロヌ」しおいるのでしょうか。 明瀺的なスロヌなしでcatch:を䜿甚するのは適切ですか 予玄語は必ずしもcatch:ある必芁はありたせん。 他の人はより良いアむデアを持っおいるかもしれたせん。 予玄語の代わりに挔算子にするこずもできたす。

Goを曞いた人は誰でも、コヌドの䞻芁な目的から泚意をそらす゚ラヌ凊理ボむラヌプレヌトの䞍幞な急増に遭遇したした。

それは真実ではありたせん。 私はGoでプログラムをかなり行っおいたすが、ボむラヌプレヌトの゚ラヌ凊理に問題はありたせん。 ゚ラヌ凊理コヌドを曞くこずは、私がほずんど気付かないほどプロゞェクトを開発するのに非垞にわずかな時間を消費したす、そしおそれは蚀語ぞの倉曎を正圓化しない私芋です。

Goを曞いた人は誰でも、コヌドの䞻芁な目的から泚意をそらす゚ラヌ凊理ボむラヌプレヌトの䞍幞な急増に遭遇したした。

それは真実ではありたせん。 私はGoでプログラムをかなり行っおいたすが、ボむラヌプレヌトの゚ラヌ凊理に問題はありたせん。 ゚ラヌ凊理コヌドを曞くこずは、私がほずんど気付かないほどプロゞェクトを開発するのに非垞にわずかな時間を消費したす、そしおそれは蚀語ぞの倉曎を正圓化しない私芋です。

゚ラヌ凊理コヌドの蚘述にかかる時間に぀いおは䜕も蚀いたせんでした。 私はそれがコヌドの䞭心的な目的から気をそらすず蚀っただけです。 たぶん私は「Goを読んだ人は皆、䞍幞なこずに゚ラヌ凊理の急増に遭遇した...」ず蚀ったはずです。

だから、 @ cznic 、あなたにずっおの質問は、ボむラヌプレヌトの凊理に過床の゚ラヌがあるず感じたGoコヌドを読んだこずがあるのか​​、それずも理解しようずしおいるコヌドの邪魔になったのかずいうこずだず思いたす。

誰も私の提案が奜きではありたせん😅
ずにかく、いく぀かの構文があり、最良のものいく぀かの投祚システムに投祚し、ここたたはreadmeにリンクを含める必芁がありたす

たぶん私は「Goを読んだ人は皆、䞍幞なこずに゚ラヌ凊理の急増に遭遇した...」ず蚀ったはずです。

それは真実ではない。 私は、珟圚の最先端の゚ラヌ凊理の明瀺性ず適切な局所性を奜みたす。 この提案は、私が今たで芋た他のどの提案ず同様に、コヌドIMHOを読みにくくし、維持するのを悪化させたす。

だから、 @ cznic 、あなたにずっおの質問は、ボむラヌプレヌトの凊理に過床の゚ラヌがあるず感じたGoコヌドを読んだこずがあるのか​​、それずも理解しようずしおいるコヌドの邪魔になったのかずいうこずだず思いたす。

いいえ。私の経隓では、Goは非垞に読みやすいプログラミング蚀語です。 もちろん、そのクレゞットの半分はgofmtに送られたす。

私自身の経隓では、䟝存するステヌトメントがたくさんあるず、実際にドラッグが始たりたす。各ステヌトメントぱラヌをスロヌする可胜性があり、゚ラヌ凊理は合蚈されおすぐに叀くなりたす。 5行のコヌドは20になりたす。

@cznic
私の経隓では、ボむラヌプレヌトの凊理で゚ラヌが発生するず、コヌドが読みにくくなりたす。 ゚ラヌ凊理自䜓はほずんど同じであるため発生する可胜性のある゚ラヌラッピングはありたせん、䞀皮のフェンス効果が発生したす。コヌドの䞀郚をすばやくスキャンするず、ほずんどの堎合、倧量の゚ラヌ凊理が衚瀺されたす。 したがっお、最倧の問題である、プログラムの最も重芁な郚分である実際のコヌドは、この目の錯芚の背埌に隠されおおり、コヌドの䞀郚が䜕であるかを実際に確認するこずは非垞に困難です。

゚ラヌ凊理は、コヌドの䞻芁郚分であっおはなりたせん。 残念ながら、それはたさにそれで終わるこずがよくありたす。
他の蚀語でのステヌトメント構成が非垞に人気があるのには理由がありたす。

゚ラヌ凊理自䜓はほずんど同じであるため゚ラヌはありたせん
発生する可胜性のあるラッピング、それは䞀皮のフェンス効果を生成したす。
コヌドの䞀郚をすばやくスキャンするず、ほずんどの堎合、倧量のコヌドが衚瀺されたす。
゚ラヌ凊理の。

これは非垞に䞻芳的な立堎です。 それは、ifステヌトメントが
コヌドを刀読䞍胜にするか、KRスタむルの䞭括匧で刀読䞍胜にしたす。

私の芋解では、goの゚ラヌ凊理の明瀺性はすぐに薄れおいきたす
パタヌンが壊れおいるこずに気付くたで、芪しみやすさの背景に。
人間の目が非垞に埗意なこず。 欠萜しおいる゚ラヌ凊理、
゚ラヌ倉数は_などに割り圓おられたす。

入力するのは負担です。間違いはありたせん。 しかし、Goは最適化されおいたせん
コヌド䜜成者、それはリヌダヌのために明瀺的に最適化したす。

2017幎5月16日火曜日午埌5時45分、Viktor Kojouharov < [email protected]

曞きたした

@cznic https://github.com/cznic
私の経隓では、ボむラヌプレヌトの凊理で゚ラヌが発生するず、コヌドが䜜成されたす
はるかに読みにくい。 ゚ラヌ凊理自䜓はほずんど同じであるため
発生する可胜性のある゚ラヌラッピングはありたせん、䞀皮のフェンスを生成したす
効果、コヌドの䞀郚をすばやくスキャンするず、ほずんどの堎合終了したす
倧量の゚ラヌ凊理が衚瀺されたす。 したがっお、最倧の問題は、実際の
プログラムの最も重芁な郚分であるコヌドは、このオプティカルの背埌に隠されおいたす
幻想、実際に䜕の郚分を芋るのが非垞に難しい
コヌドは玄です。

゚ラヌ凊理は、コヌドの䞻芁郚分であっおはなりたせん。 残念ながら、かなり
倚くの堎合、それはたさにそれであるこずになりたす。

—
このスレッドにサブスクラむブしおいるため、これを受け取っおいたす。
このメヌルに盎接返信し、GitHubで衚瀺しおください
https://github.com/golang/go/issues/19991#issuecomment-301702623 、たたはミュヌト
スレッド
https://github.com/notifications/unsubscribe-auth/AAAcA4ydpBFiapYBOBUyUjg6du5Dnjs5ks5r6VQjgaJpZM4M-dud
。

コヌドの䞀郚をすばやくスキャンするず、ほずんどの堎合、倧量のコヌドが衚瀺されたす。
゚ラヌ凊理の。

これは非垞に䞻芳的な立堎です。

非垞に䞻芳的でありながら広く共有されおいたす。

ロブ自身が蚀ったように、

Goプログラマヌ、特にこの蚀語に䞍慣れなプログラマヌの間でよくある議論のポむントは、゚ラヌの凊理方法です。 䌚話は、シヌケンスの回数でしばしば嘆きに倉わりたす

if err != nil {
    return err
}

珟れたす。

公平を期すために、Robは、Go゚ラヌ凊理に関するこの認識は「䞍幞で、誀解を招きやすく、簡単に修正できる」ず続けたした。 しかし、圌はその蚘事のほずんどを、知芚を修正するための圌の掚奚する方法を説明する説明しおいるように、ロブの凊方自䜓には問題がありたす。 マヌティンの批刀に加えお、ロブの提案は、 @ cznicがGo゚ラヌ凊理で

たぶん問題は、私たちが眮き換える胜力を持っおいたかどうかです

res, err := doThing()
if err != nil {
  return nil, err
}

次のようなもので

res, err := doThing() catch: nil, err

それを䜿甚したすか、それずも4行バヌゞョンを䜿い続けたすか あなたの個人的な奜みに関係なく、このような代替案はGoコミュニティで広く採甚され、慣甚的になるず思いたすか 短いバヌゞョンが読みやすさに悪圱響を䞎えるずいう議論の䞻芳性を考えるず、プログラマヌずの私の経隓では、圌らは単䞀行バヌゞョンに匷く匕き寄せられるだろうず蚀っおいたす。

実際の話go 1は固定されおおり、特にこの基本的な方法では倉曎されたせん。

Go 2がいく぀かのテンプレヌトタむプを実装するたで、ある皮のオプションタむプを提案するこずは無意味です。 その時点で、すべおが倉わりたす。

2017幎5月16日には、午埌11時46分で、ビリヌHinners [email protected]曞きたした

コヌドの䞀郚をすばやくスキャンするず、ほずんどの堎合、倧量のコヌドが衚瀺されたす。
゚ラヌ凊理の。

これは非垞に䞻芳的な立堎です。

非垞に䞻芳的でありながら広く共有されおいたす。

ロブ自身が蚀ったように、

Goプログラマヌ、特にこの蚀語に䞍慣れなプログラマヌの間でよくある議論のポむントは、゚ラヌの凊理方法です。 䌚話は、シヌケンスの回数でしばしば嘆きに倉わりたす

err= nil {の堎合
゚ラヌを返す
}
珟れたす。

公平を期すために、Robは、Go゚ラヌ凊理に関するこの認識は「䞍幞で、誀解を招きやすく、簡単に修正できる」ず続けたした。 しかし、圌はその蚘事のほずんどを、知芚を修正するための圌の掚奚する方法を説明するこずに費やしおいたす。 残念ながら、マヌティン・クヌルがよく説明しおいるように、ロブの凊方自䜓には問題がありたす。 マヌティンの批刀に加えお、ロブの提案は、 @ cznicがGo゚ラヌ凊理で

たぶん問題は、私たちが眮き換える胜力を持っおいたかどうかです

res、err= doThing
err= nil {の堎合
nilを返し、゚ラヌ
}
次のようなもので

res、err= doThingcatchnil、err

それを䜿甚したすか、それずも4行バヌゞョンを䜿い続けたすか あなたの個人的な奜みに関係なく、このような代替案はGoコミュニティで広く採甚され、慣甚的になるず思いたすか 短いバヌゞョンが読みやすさに悪圱響を䞎えるずいう議論の䞻芳性を考えるず、プログラマヌずの私の経隓では、圌らは単䞀行バヌゞョンに匷く匕き寄せられるだろうず蚀っおいたす。

—
コメントしたのでこれを受け取っおいたす。
このメヌルに盎接返信するか、GitHubで衚瀺するか、スレッドをミュヌトしおください。

Go 2がいく぀かのテンプレヌトタむプを実装するたで、ある皮のオプションタむプを提案するこずは無意味です。 その時点で、すべおが倉わりたす。

このスレッドのタむトルが瀺すように、Go 2に぀いお話しおいるず思いたした。たた、「Go 2」は、「決しお」の婉曲衚珟ではないず完党に信じおいたす。 実際、Go 1が修正されおいるこずを考えるず、Goの議論の倧郚分をGo2に費やす必芁がありたす。

そうは蚀っおも、Goの冗長性に぀いお䞍満を蚀う人は誰でも
゚ラヌ凊理には、゚ラヌの目的ずいう基本的なポむントが欠けおいたす
Goでの凊理は、゚ラヌではないケヌスを簡朔で目立たないものにするために_not_です
できるだけ。 むしろ、Goの゚ラヌ凊理戊略の目暙は、匷制するこずです
垞に、次の堎合に䜕が起こるかを考慮するコヌドの䜜成者
機胜が倱敗し、そしお最も重芁なのは、クリヌンアップ、元に戻す、および回埩する方法
発信者に戻る前に。

゚ラヌ凊理ボむラヌプレヌトを隠すためのすべおの戊略は、私には
これを無芖したす。

2017幎5月16日火曜日、2351 Dave

本圓の話go 1は修正されおおり、特にこれでは倉曎されたせん
基本的な方法。

Go 2が実装するたで、ある皮のオプションタむプを提案するのは無意味です
テンプレヌトタむプの䞀郚。 その時点で、すべおが倉わりたす。

2017幎5月16日には、午埌11時46分で、ビリヌHinners [email protected]曞きたした

コヌドの䞀郚をすばやくスキャンするず、ほずんどの堎合、
質量
゚ラヌ凊理の。

これは非垞に䞻芳的な立堎です。

非垞に䞻芳的でありながら広く共有されおいたす。

ロブ自身が蚀ったように、

Goプログラマヌ、特に初心者のプログラマヌの間での共通の論点
蚀語は、゚ラヌを凊理する方法です。 䌚話はしばしば
シヌケンスの回数で嘆く

err= nil {の堎合
゚ラヌを返す
}

珟れたす。

公平を期すために、Robは、Go゚ラヌ凊理に関するこの認識は次のように述べおいたす。
「残念ながら、誀解を招きやすく、簡単に修正できたす。」 しかし、圌はそのほずんどを費やしおいたす
圌を説明する蚘事https://blog.golang.org/errors-are-values
知芚を修正するための掚奚される方法。 残念ながら、ロブの
説明されおいるように、凊方自䜓は問題がありたす
https://www.innoq.com/en/blog/golang-errors-monads/マヌティンによっおずおもよく
キュヌル。 マヌティンの批評に加えお、ロブの提案はたた、
@cznichttps //github.com/cznicがGoで評䟡しおいるず蚀っおいる地域
゚ラヌ凊理。

たぶん問題は、私たちが眮き換える胜力を持っおいたかどうかです

res、err= doThing
err= nil {の堎合
nilを返し、゚ラヌ
}

次のようなもので

res、err= doThingcatchnil、err

それを䜿甚したすか、それずも4行バヌゞョンを䜿い続けたすか
あなたの個人的な奜みに関係なく、あなたは次のような代替案を考えたすか
これはGoコミュニティで広く採甚され、慣甚的になりたすか
短いバヌゞョンが逆にずいう議論の䞻芳性を考えるず
読みやすさに圱響したす、プログラマヌずの私の経隓は圌らがそうするだろうず蚀いたす
単線バヌゞョンに匷く匕き寄せられたす。

—
コメントしたのでこれを受け取っおいたす。
このメヌルに盎接返信し、GitHubで衚瀺しおください
https://github.com/golang/go/issues/19991#issuecomment-301787215 、たたはミュヌト
スレッド
https://github.com/notifications/unsubscribe-auth/AAAcAwATgoJwL5WV-0nffLjLB9L86GYOks5r6ai3gaJpZM4M-dud
。

むしろ、Goの゚ラヌ凊理戊略の目暙は、匷制するこずです
垞に、次の堎合に䜕が起こるかを考慮するコヌドの䜜成者
機胜が倱敗し、そしお最も重芁なのは、クリヌンアップ、元に戻す、および回埩する方法
発信者に戻る前に。

さお、Goはその目暙を達成したせんでした。 デフォルトでは、Goを䜿甚するず、返された゚ラヌを無芖できたす。倚くの堎合、どこかで正垞に機胜しなくなるたで、そのこずを知るこずさえできたせん。 それどころか、Goコミュニティの䟋倖これは芁点を蚌明するための単なる䟋ですで倧いに嫌われおいるので、アプリケヌションがクラッシュするため、それらを考慮する必芁がありたす。 それはしばしば私たちにすべおを捕たえお無芖するずいう問題に぀ながりたすが、それはプログラマヌのせいです。

基本的に、Goでの゚ラヌ凊理はオプトむンです。 すべおの゚ラヌを凊理する必芁があるずいうのは、口頭の慣習に関するものです。 それが実際にあなたに゚ラヌを凊理するこずを匷制するならば、目暙は達成されるでしょう。 たずえば、コンパむル時の゚ラヌや譊告がありたす。

それを念頭に眮いお、ボむラヌプレヌトを隠しおも誰も傷぀けたせん。 口頭での慣習は今でも維持され、プログラマヌは今のように゚ラヌ凊理をオプトむンしたす。

Goの゚ラヌ凊理戊略の目暙は、匷制するこずです
垞に、次の堎合に䜕が起こるかを考慮するコヌドの䜜成者
機胜が倱敗し、そしお最も重芁なのは、クリヌンアップ、元に戻す、および回埩する方法
発信者に戻る前に。

それは間違いなく高貎な目暙です。 ただし、プラむマリフロヌの可読性ずコヌドの意図ずのバランスをずる必芁があるのが目暙です。

Goプログラマヌずしお、私はあなたに蚀うこずができたす。
読みやすさを損なうためのGoの゚ラヌ凊理。 䜕も芋えない
他の人が曞いたコヌドを読むこずに䞍快感を感じないので、トレヌドオフする
プログラマヌに行きなさい。

0:10時氎曜、2017幎5月17日には、ビリヌHinners [email protected]
曞きたした

Goの゚ラヌ凊理戊略の目暙は、匷制するこずです
垞に、次の堎合に䜕が起こるかを考慮するコヌドの䜜成者
機胜が倱敗し、そしお最も重芁なのは、クリヌンアップ、元に戻す、および回埩する方法
発信者に戻る前に。

それは間違いなく高貎な目暙です。 それは目暙ですが、それは
プラむマリフロヌの可読性ずコヌドの意図に察しおバランスが取れおいたす。

—
コメントしたのでこれを受け取っおいたす。
このメヌルに盎接返信し、GitHubで衚瀺しおください
https://github.com/golang/go/issues/19991#issuecomment-301794653 、たたはミュヌト
スレッド
https://github.com/notifications/unsubscribe-auth/AAAcAzfcu5hq86xxVj85qfOquVawHh44ks5r6a5zgaJpZM4M-dud
。

@davecheney 、゚ラヌ凊理は明瀺的であり、埌で延期されるべきではないこずに同意したすがもちろん、_で実行できたす、1぀の関数で゚ラヌを凊理するために゚ラヌを「バブリング」する戊略もありたす。远加情報を远加たたは削陀したすクラむアントに送信する前に。 私の個人的な問題は、同じ4行のコヌドを䜕床も曞かなければならないこずです。

䟋えば

getNewTokenid int64トヌクン、゚ラヌ{

user := &User{ID:id}

u, err := user.Get();
if err != nil {
    return Token{}, err
}

token, err := token.New(u);
if err != nil {
    return Token{}, err
}
return token, nil

}
私はここで゚ラヌを凊理しおいたせん、私はそれを返すだけです。 この皮のコヌドを読むずきは、゚ラヌの「凊理」をスキップする必芁があり、コヌドの䞻な目的を芋぀けるのが困難です。

䞊蚘のコヌドは、次のようなものに簡単に眮き換えるこずができたす。

getNewTokenid int64トヌクン、゚ラヌ{

user := &User{ID:id}

u, err := throw user.Get(); //throw should also wrap the error

token, err := throw token.New(u);

return token, nil

}
そのようなコヌドは、より読みやすく、䞍芁性の少ないIMHOコヌドです。 たた、゚ラヌは、この関数が䜿甚されおいる関数で凊理される可胜性があり、凊理する必芁がありたす。

Goプログラマヌずしお、私はGoの゚ラヌ凊理の冗長性が読みやすさを損なうこずはないずあなたに蚀うこずができたす。

同意したす。

無関係なメモに぀いお

たた、「結果」タむプは提案に察しお少し具䜓的すぎるように思われたす。 たぶん、型は実際には2぀のバリアントの列挙型です。 列挙型の抂念がある堎合は、結果たたはオプションパッケヌゞをツリヌから䜜成し、それを蚀語に远加する前に実隓しお、実際には再利甚できず、優れおいるだけの䜙分な構文やメ゜ッドをたくさん远加する必芁はありたせん。結果タむプの堎合。 列挙型がGoで圹立぀かどうかはわかりたせんが、より䞀般的なケヌスに぀いお議論できれば、より具䜓的な結果タむプの堎合もおそらくより匷力になりたすおそらく私は間違っおいたす。

func getNewTokenid int64トヌクン、゚ラヌ{
user=User {IDid}

u, err := user.Get()
if err != nil {
    return Token{}, err
}

return token.New(u)

}

同等のようです。

0:34時氎曜、2017幎5月17日には、Kiura [email protected]は曞きたした

@davecheney https://github.com/davecheney 、私はあなたに同意したすが
その゚ラヌ凊理は明瀺的であり、埌で延期されるべきではありたせん
もちろん、あなたは_で行うこずができたす、「バブリング」する戊略もありたす
1぀の機胜でそれらを凊理するための゚ラヌ、远加情報を远加するための゚ラヌ、たたは
削陀したすクラむアントに送信する前に。 私の個人的な問題は私が持っおいるこずです
同じ4行のコヌドを䜕床も曞く

䟋えば

getNewTokenid int64トヌクン、゚ラヌ{

user=User {IDid}

u、err= user.Get;
err= nil {の堎合
トヌクン{}を返す、゚ラヌ
}

トヌクン、゚ラヌ= token.Newu;
err= nil {の堎合
トヌクン{}を返す、゚ラヌ
}
トヌクンを返す、nil

}
私はここで゚ラヌを凊理しおいたせん、私はそれを返すだけです。 そしお私が読んだずき
この皮のコヌドでは、゚ラヌの「凊理」をスキップする必芁があり、芋぀けるのが困難です
コヌドの䞻な目的

䞊蚘のコヌドは、次のようなものに簡単に眮き換えるこずができたす。

getNewTokenid int64トヌクン、゚ラヌ{

user=User {IDid}

u、err= throw user.Get; // throwも゚ラヌをラップする必芁がありたす

トヌクン、゚ラヌ= throw token.Newu;

トヌクンを返す、nil

}
そのようなコヌドは、より読みやすく、䞍芁性の少ないIMHOコヌドです。 そしおその
゚ラヌは、この関数が存圚する関数で凊理される可胜性があり、凊理する必芁がありたす
䜿甚枈み。

—
あなたが蚀及されたので、あなたはこれを受け取っおいたす。
このメヌルに盎接返信し、GitHubで衚瀺しおください
https://github.com/golang/go/issues/19991#issuecomment-301802010 、たたはミュヌト
スレッド
https://github.com/notifications/unsubscribe-auth/AAAcA9sIRXX7RSdDcUOidpe-qLTR7unNks5r6bP3gaJpZM4M-dud
。

たた、「結果」タむプは提案に察しお少し具䜓的すぎるように思われたす。 たぶん、型は実際には2぀のバリアントの列挙型です。 列挙型の抂念がある堎合は、結果たたはオプションパッケヌゞをツリヌから䜜成し、それを蚀語に远加する前に実隓しお、実際には再利甚できず、優れおいるだけの䜙分な構文やメ゜ッドをたくさん远加する必芁はありたせん。結果タむプの堎合。 列挙型がGoで圹立぀かどうかはわかりたせんが、より䞀般的なケヌスに぀いお議論できれば、より具䜓的な結果タむプの堎合もおそらくより匷力になりたすおそらく私は間違っおいたす。

元の提案で述べられおいるように、結果タむプは理想的には合蚈タむプずしお実装されたずえば、列挙型ala Rustの、蚀語にそれらを远加するためのオヌプンな提案がありたす。

ただし、远加の蚀語サポヌトなしで再利甚可胜な結果タむプラむブラリを実装するには、合蚈タむプだけでは䞍十分です。 たた、ゞェネリックが必芁です。

この提案は、ゞェネリックスに䟝存せず、代わりにコンパむラヌからの特殊なケヌスのヘルプに䟝存する結果タむプを実装するずいうアむデアを暡玢しおいたした。

これを投皿したので、これを远求するための最良の方法は、蚀語レベルのゞェネリックスのサポヌトを䜿甚するこずであるこずに同意したす。

@davecheney 、確かに、この堎合はほずんど違いはありたせんが、゚ラヌを返す関数で3〜4回の呌び出しがある堎合はどうなりたすか

PS私ぱラヌを凊理するGo1構造に反察しおいたせん、私はそれがより良いかもしれないず思いたす。

元の提案で述べられおいるように、結果タむプは理想的には合蚈タむプずしお実装されたずえば、列挙型ala Rustの、蚀語にそれらを远加するためのオヌプンな提案がありたす。

申し蚳ありたせんが、私はもっず明確にすべきでした私はこの声明を䞻匵しおいたした

Goの結果タむプも必芁ではなく、特殊なケヌスのコンパむラヌの魔法を利甚するだけでよいず思いたす。

私には悪い考えのように感じたす。

ただし、远加の蚀語サポヌトなしで再利甚可胜な結果タむプラむブラリを実装するには、合蚈タむプだけでは䞍十分です。 たた、ゞェネリックが必芁です。

この提案は、ゞェネリックスに䟝存せず、代わりにコンパむラヌからの特殊なケヌスのヘルプに䟝存する結果タむプを実装するずいうアむデアを暡玢しおいたした。

これを投皿したので、これを远求するための最良の方法は、蚀語レベルのゞェネリックスのサポヌトを䜿甚するこずであるこずに同意したす。

はい、十分に公平です。 私はあなたの最埌の声明に同意したす。 ずにかくGo2を埅たなければならない堎合は、最初にもっず䞀般的な問題を解決したほうがよいでしょう実際に問題であるず仮定しお:)

たた、Rob Pikeは、䞊蚘のように゚ラヌ凊理に関する蚘事を曞きたした。 このアプロヌチは問題を「修正」しおいるように芋えたすが、別の問題が発生したす。それは、むンタヌフェヌスによるコヌドの膚匵です。

「明瀺的な゚ラヌ凊理」ず「詳现な゚ラヌ凊理」を混同しないこずが重芁だず思いたす。 Goは、ナヌザヌに゚ラヌ凊理を委任するのではなく、すべおのステップで゚ラヌ凊理を怜蚎するように匷制したいず考えおいたす。 ゚ラヌをスロヌする可胜性のある呌び出す関数ごずに、゚ラヌを凊理するかどうか、およびその方法を決定する必芁がありたす。 ゚ラヌを無芖するこずを意味する堎合もあれば、再詊行するこずを意味する堎合もありたす。倚くの堎合、゚ラヌを呌び出し元に枡しお凊理するこずを意味したす。

Robの蚘事は玠晎らしく、Effective Go 2の䞀郚である必芁がありたすが、これはこれたでのずころしか理解できない戊略です。 特に異皮の呌び出し先を凊理する堎合、管理する゚ラヌ凊理がたくさんありたす

゚ラヌ凊理に圹立぀シンタックスシュガヌやその他の機胜を怜蚎するのは䞍合理ではないず思いたす。 Go゚ラヌ凊理の基本を損なわないこずが重芁だず思いたす。 たずえば、発生するすべおの゚ラヌを凊理する関数レベルの゚ラヌハンドラヌを確立するのは悪いこずです。 これは、䟋倖凊理が通垞行うこずをプログラマヌが実行できるようにするこずを意味したす。぀たり、゚ラヌの考慮をステヌトメントレベルの問題からブロックレベルたたは関数レベルの問題に移したす。 それは間違いなく哲孊に反しおいたす。

@billyh 「Goでの゚ラヌ凊理パタヌン」の蚘事に関しおは、他の解決策がありたす。

@egonelbre
これらの゜リュヌションは、同じタむプの操䜜を繰り返し実行しおいる堎合にのみ適しおいたす。 通垞はそうではありたせん。 したがっお、これを実際に適甚するこずはほずんどできたせん。

@urandomでは、珟実的な䟋を瀺しおください。

確かに私はもっず耇雑な䟋を取るこずができたす

func (conversion *PageConversion) Convert() (page *kb.Page, errs []error, fatal error)

これらはどこにでも圓おはたるわけではないこずは理解しおいたすが、改善したい䟋の適切なリストがなければ、たずもな議論をする方法はありたせん。

@egonelbre

https://github.com/juju/juju/blob/01b24551ecdf20921cf620b844ef6c2948fcc9f8/cloudconfig/providerinit/providerinit.go

免責事項私はjujuを䜿甚したこずも、コヌドを読んだこずもありたせん。 それは私が頭のおっぺんに知っおいる単なる「生産」補品です。 このようなタむプの゚ラヌ凊理独立した操䜜の間に゚ラヌがチェックむンされるがgoの䞖界で普及しおいるこずは合理的に確信しおおり、これに遭遇しおいない人はいないず思いたす。

@urandom同意したす。 実際のコヌドなしで議論する際の䞻な問題は、人々が実際の問題ではなく、問題の「芁点」を芚えおいるこずです。これは、問題の蚘述を過床に単玔化するこずに぀ながるこずがよくありたす。 _PS goで1぀のたした。_

たずえば、これらの実際の䟋から、考慮する必芁のある他のいく぀かのこずがわかりたす。

  • 良い゚ラヌメッセヌゞ
  • ゚ラヌ倀に基づく回埩/代替パス
  • フォヌルバック
  • ゚ラヌのあるベスト゚フォヌト実行
  • ハッピヌケヌスロギング
  • 倱敗ログ
  • 障害トレヌス
  • 耇数の゚ラヌが返されたす
  • _もちろん、これらのいく぀かは䞀緒に䜿甚されたす_
  • ...おそらく私が逃したもの...

「幞せ」ず「倱敗」の道だけではありたせん。 私はこれらが解決できないず蚀っおいるのではなく、ただそれらを蚈画しお議論する必芁があるずいうこずです。

@egonelbreは、今週のGolang Weeklyの別の䟋で、MarioZupanによる「Goで静的ブログゞェネレヌタヌを䜜成する」ずいうタむトルの蚘事にありたす。

func (ds *GitDataSource) Fetch(from, to string) ([]string, error) {
    fmt.Printf("Fetching data from %s into %s...\n", from, to)
    if err := createFolderIfNotExist(to); err != nil {
        return nil, err
    }
    if err := clearFolder(to); err != nil {
        return nil, err
    }
    if err := cloneRepo(to, from); err != nil {
        return nil, err
    }
    dirs, err := getContentFolders(to)
    if err != nil {
        return nil, err
    }
    fmt.Print("Fetching complete.\n")
    return dirs, nil
}

泚マリオのコヌドに察する批刀を暗瀺しおいるわけではありたせん。 実際、私は圌の蚘事をずおも楜しんだ。
残念ながら、このような䟋はすべおGo゜ヌスでは䞀般的すぎたす。 Goコヌドは、関心のある1行のこの線路パタヌンに匕き寄せられ、その埌に3行の同䞀たたはほが同䞀のボむラヌプレヌトが䜕床も繰り返されたす。 マリオのように、可胜な堎合は割り圓おず条件付きを組み合わせるず、少し圹立ちたす。

コヌドの行を最小限に抑えるこずを䞻な目的ずしおプログラミング蚀語が蚭蚈されおいるかどうかはわかりたせんが、a意味のあるコヌドず定型文の比率は、プログラミング蚀語の品質の倚くの有効な尺床の1぀である可胜性がありたす。bプログラミングの倚くぱラヌ凊理を䌎うため、このパタヌンはGoコヌドに浞透し、したがっお、過剰なボむラヌプレヌトのこの特定のケヌスを合理化するメリットがありたす。

良い代替案を特定できれば、それは急速に採甚され、Goの読み取り、曞き蟌み、保守がさらに楜しくなるず思いたす。

Rebecca Skinner@cercerillaは、Goの゚ラヌ凊理の欠点に関する優れた蚘事ず、スラむドデッキのMonadic Error Handling inGoの゜リュヌションずしおモナドを䜿甚した分析を共有したした。 私は最埌に圌女の結論が特に奜きでした。

圌の蚘事でレベッカのデッキを参照するための@davecheneyのおかげでシンプル債務Reduxのそれを芋぀けるために私を可胜にしたした。 Go 2に察する私のバラ色の楜芳䞻矩をより厳しい珟実に基づいお行っおくれたDaveにも感謝したす。

Goコヌドは、関心のある1行のこの線路パタヌンに匕き寄せられ、その埌に3行の同䞀たたはほが同䞀のボむラヌプレヌトが䜕床も繰り返されたす。

すべおの制埡フロヌ制埡ステヌトメントは重芁です。 ゚ラヌ凊理ラむンは、正確性の芳点から非垞に重芁です。

ボむラヌプレヌトに察する意味のあるコヌドの比率は、プログラミング蚀語の品質の倚くの有効な尺床の1぀である可胜性がありたす

゚ラヌ凊理ステヌトメントが意味をなさないず誰かが考えた堎合は、コヌディングを頑匵っおください。結果に近づかないようにしたいず思いたす。

@davecheneyのSimplicityDebt Reduxでカバヌされおいるポむントの1぀に察凊するにはこれに぀いおはカバヌしたしたが、繰り返す必芁があるず思いたす。

次の質問は、このモナディック圢匏が゚ラヌを凊理する単䞀の方法になるかどうかです。

このようなものが゚ラヌを凊理する「単䞀の」方法になるためには、暙準ラむブラリ党䜓ずすべおの「Go2」互換プロゞェクトで行われる重倧な倉曎である必芁がありたす。 それは賢明ではないず思いたす。Python2/ 3の倧倱敗は、そのような分裂が蚀語゚コシステムにどのように損害を䞎える可胜性があるかを瀺しおいたす。

この提案で述べたように、結果タむプが自動的に同等のタプルフォヌムに匷制倉換できる堎合は、既存のコヌドずの䞋䜍互換性を維持しながら、このアプロヌチを党面的に採甚する架空のGo2暙準ラむブラリの芳点からケヌキを持っお食べるこずができたす。 これにより、興味のある人はそれを利甚できたすが、それでもGo1で䜜業したいラむブラリは、そのたた䜿甚できたす。 ラむブラリの䜜成者は、叀いスタむルを䜿甚しおGo1ずGo2の䞡方で動䜜するラむブラリを䜜成するか、Monadicスタむルを䜿甚しおGo2のみで動䜜するラむブラリを䜜成するかを遞択できたす。

゚ラヌ凊理の「叀い方法」ず「新しい方法」は、蚀語のナヌザヌがそれに぀いお考える必芁がなく、必芁に応じお「叀い方法」で䜜業を続けるこずができるずいう点で互換性がありたす。 これには特定の抂念的な玔粋さが欠けおいたすが、既存のコヌドを倉曎せずに動䜜させ続け、最新だけでなくすべおのバヌゞョンの蚀語で動䜜するラむブラリを開発できるようにするよりもはるかに重芁ではないず思いたす。

゚ラヌむンタヌフェむスモデルず新しいモナディック型の䞡方を匕き続きサポヌトするこずは、玛らわしいようであり、Go2.0の初心者に䞍明確なガむダンスを提䟛したす。

それらはブレヌキです。蚀語をそのたた凍結するか、蚀語を進化させお、偶発的な耇雑さを远加し、以前のやり方をレガシヌいがに委ねたす。 叀い機胜が廃止されたが互換性があるか、たたは重倧な倉曎の圢で戞倖にあるかにかかわらず、叀い機胜を眮き換える新しい機胜を远加するこずは、この蚀語のナヌザヌが考えるものであるため、これらは本圓に2぀のオプションだけだず思いたす関係なく孊ぶ必芁がありたす。

蚀語を倉えるこずはできないず思いたすが、たずえGo2がこれを完党に採甚したずしおも、新参者に「叀い方法」ず「新しい方法」の䞡方を孊ぶこずを避けおもらいたす。 あなたはただGo1ずGo2の分裂を残されおいるでしょう、そしお新参者は違いが䜕であるか疑問に思うでしょう、そしおずにかく「Go1」を孊ばなければならないこずになるでしょう。

䞋䜍互換性は、蚀語ずコヌドの互換性を教えるのに圹立぀ず思いたす。構文が叀くなっおいおも、Goを教える既存の資料はすべお匕き続き有効です。 Goの教材をすべお調べお、叀い構文を無効にする必芁はありたせん。教材は、暇なずきに、新しい構文があるずいう通知を远加するこずができたす。

「それを行うには耇数の方法がある」ずいうのは、䞀般的に単玔性ずミニマリズムずいうGoの哲孊に反するこずを理解しおいたすが、新しい蚀語機胜を远加するために支払わなければならない代償です。 新しい蚀語機胜は、その性質䞊、叀いアプロヌチを廃止したす。

私は確かに、Gopherにずっおより自然な方法で同じコア問題を解決する方法があるかもしれないこずを認めたいず思いたすが、既存のアプロヌチからのそのような䞍快な倉曎ではありたせん。

考慮すべきもう1぀のこずGoは蚀語を習埗しやすくするずいう暡範的な仕事をしおきたしたが、それだけが人々を蚀語に参加させるこずに䌎う障害ではありたせん。 Goの゚ラヌ凊理の冗長性を芋お、それによっお延期されおいる人がたくさんいるず蚀っおも過蚀ではありたせん。その䞭には、蚀語の採甚を拒吊する人もいたす。

蚀語の改善が珟圚それによっお延期されおいる人々を匕き付けるこずができるかどうか、そしおこれが蚀語を孊びにくくするこずずどのようにバランスをずるかを尋ねる䟡倀があるず思いたす。

ただし、モナディック゚ラヌ凊理のようなこずを行うず、゚ラヌに぀いお考えさせるずいうGoの哲孊に反したす。 モナディック゚ラヌ凊理ずJavaスタむルの䟋倖凊理は、セマンティクスが非垞に䌌おいたすただし、構文は異なりたす。 Goは、考えたずきに゚ラヌ凊理コヌドを远加するだけでなく、プログラマヌが各゚ラヌを明瀺的に凊理するこずを期埅するずいう、意図的に異なる哲孊を採甚したした。 実際、 return nil, errむディオムは厳密に蚀えば最適ではありたせん。これは、おそらく远加の有甚なコンテキストを远加できるためです。

Goの゚ラヌ凊理に察凊する詊みは、これを念頭に眮いおおく必芁があり、゚ラヌに぀いお考えるのを簡単に避けられないようにする必芁があるず思いたす。

@alercah私はあなたが今蚀ったすべおのものずは違うこずを懇願する必芁がありたす...

モナディック゚ラヌ凊理のようなこずをするこずは、゚ラヌに぀いお考えさせるずいうGoの哲孊に反したす。

Rustから来おいるので、RustたたはRustコンパむラは実際にはGoよりも゚ラヌに぀いお考えさせられるず思いたす。 RustのResultタむプには[must_use]属性がありたす。これは、未䜿甚の結果がコンパむラ譊告を生成するこずを意味したす。 これはGoではそうではありたせんRebecca Skinnerは圌女の講挔でこれに取り組んでいたすGoコンパむラは、たずえば未凊理のerror倀に぀いお譊告したせん。

Rust型システムは、コヌドで察凊されるすべおの゚ラヌケヌスを匷制したす。そうでない堎合、それは型゚ラヌ、たたはせいぜい譊告です。

モナディック゚ラヌ凊理ずJavaスタむルの䟋倖凊理は、セマンティクスが非垞に䌌おいたすただし、構文は異なりたす。

これが真実ではない理由を分析したしょう。

゚ラヌ䌝播戊略

  • Go戻り倀、明瀺的に䌝播
  • Java非ロヌカルゞャンプ、暗黙的に䌝播
  • Rust戻り倀、明瀺的に䌝播

゚ラヌの皮類

  • Go関数ごずに1぀の戻り倀、通垞は(success, error)タプル
  • Javaメ゜ッドからスロヌされる可胜性のあるすべおの䟋倖の集合和を衚す、倚くの䟋倖タむプで構成されるチェック枈み䟋倖。 たた、宣蚀されおおらず、い぀でもどこでも発生する可胜性のある未チェックの䟋倖。
  • Rust関数ごずに1぀の戻り倀、通垞はResult合蚈タむプ䟋 Result<Success, Error>

党䜓ずしお、゚ラヌ凊理に関しおは、GoはJavaよりもRustにはるかに近いず感じおいたす。GoずRustの゚ラヌは単なる倀であり、䟋倖ではありたせん。 䌝播を明瀺的にオプトむンする必芁がありたす。 異なるタむプの゚ラヌを、たずえばラッピングによっお、特定の関数が返す゚ラヌに倉換する必芁がありたす。 これらは䞡方ずも、異なるタむプのシステム機胜タプルず䞀般的な合蚈タむプを䜿甚するだけで、最終的に成功倀ず゚ラヌのペアを衚したす。

Rustが、クレヌトごずに遞択的に䜿甚しお暗黙的な゚ラヌ凊理を行うこずができるいく぀かの抜象化を提䟛するいく぀かの䟋倖がありたす぀たり、明瀺的な゚ラヌ倉換では、手動で゚ラヌを䌝播する必芁がありたす。 たずえば、 Fromトレむトを䜿甚しお、゚ラヌをあるタむプから別のタむプに自動的に倉換できたす。 個人的には、゚ラヌをある明瀺的なタむプから別の明瀺的なタむプに自動的に倉換できる特定のパッケヌゞに完党にスコヌプされたポリシヌを定矩できるこずは、欠点ではなく利点だず思いたす。 Rustの特性システムでは、自分のクレヌト内のタむプに察しおFromのみを定矩できるため、距離を眮いた䞍気味なアクションを防ぐこずができたす。

ただし、これはこの提案の範囲倖であり、Goが連携しお機胜しないいく぀かの蚀語機胜が含たれおいるため、Goがこれらのタむプの暗黙的な倉換をサポヌトする「リスク」があるような滑りやすい坂道はないず思いたす。 、少なくずもGoがゞェネリックスず特性/型クラスを远加するたでは。

この問題に぀いお私の2セントを投げる。 この皮の機胜は、単䞀のアプリケヌションが倚数の補助デヌタ゜ヌスず通信し、簡単な方法で結果を䜜成する䌁業私自身の雇甚䞻などにずっお非垞に圹立぀ず思いたす。

これが私たちが持っおいるであろういく぀かのコヌドフロヌの代衚的なデヌタサンプルです

func generateUser(userID : string) (User, error) {
      siteProperties, err := clients.GetSiteProperties()
      if err != nil {
           return nil, err
     }
     chatProperties, err := clients.GetChatProperties()
      if err != nil {
           return nil, err
     }

     followersProperties, err := clients.GetFollowersProperties()
      if err != nil {
           return nil, err
     }


// ... (repeat X5)
     return createUser(siteProperties, ChatProperties, followersProperties, ... /*other properties here */), nil
}

Goは、ナヌザヌに各ポむントで゚ラヌに぀いお考えさせるように蚭蚈されおいるずいう倚くのプッシュバックを理解しおいたすが、関数の倧郚分がT, err返すコヌドベヌスでは、これは実質的な実際のコヌドの膚匵に぀ながりたす誰かが远加の関数呌び出しを行った埌に゚ラヌ凊理コヌドを远加するのを忘れ、゚ラヌが黙っおチェックされないため、実際には本番環境の倱敗に぀ながりたした。 さらに、実際、私たちの最もおしゃべりなサヌビスのいく぀かが最倧20以䞊の゚ラヌ凊理であるのは珍しいこずではなく、興味深いものはほずんどありたせん。

さらに、この゚ラヌ凊理ロゞックの倧郚分は同䞀であり、逆説的に、コヌドベヌスでの明瀺的な゚ラヌ凊理の量が倚いため、干し草の山に少し針があるため、䟋倖的なケヌスが実際に興味深いコヌドを芋぀けるのは困難です。 '挔劇の珟象。

特にこの提案が解決策ではない理由は確かにわかりたすが、この定型文を削枛するための「䜕らかの」方法が必芁であるず私は信じおいたす。

もう少し怠惰な考え

Rustの末尟の?は、優れた構文です。 ただし、Goの堎合、゚ラヌコンテキストの重芁性を考えるず、次のバリ゚ヌションを提案する可胜性がありたす。

  • 末尟の? 、Go甚に倉曎されたRustのように機胜したす。 具䜓的には、最埌の戻り倀がタむプerror関数でのみ䜿甚でき、最埌の戻り倀もタむプerror関数呌び出しの盎埌に衚瀺される必芁がありたす泚 errorも実装するすべおの型を蚱可したすが、 errorを芁求するず、nilむンタヌフェむスの問題が発生するのを防ぐこずができたす。これは玠晎らしいボヌナスです。 その結果、゚ラヌ倀がnil以倖の堎合、 ?が衚瀺される関数が関数から返され、最埌のパラメヌタヌが゚ラヌ倀に蚭定されたす。 名前付きの戻り倀を䜿甚する関数の堎合、他の倀に察しおれロを返すか、珟圚栌玍されおいる倀を返すこずができたす。 そうでない関数の堎合、他の戻り倀は垞にれロです。
  • 末尟の.?("opening %s", file)は䞊蚘のように機胜したすが、゚ラヌを倉曎せずに返すのではなく、゚ラヌを構成する関数を介しお枡される点が異なりたす。 倧たかに蚀えば、 .?(str, vals...)はfmt.Errorf(str + ": %s", vals..., err)ように䟵食を倉化させたす
  • おそらく、パッケヌゞが識別された゚ラヌタむプを゚クスポヌトする堎合をカバヌする、 .?構文のバリアントたたは別のバヌゞョンのいずれかが存圚する必芁がありたす。

19412合蚈タむプおよび21161゚ラヌ凊理および15292ゞェネリックに関連したす。

関連しおいる

新しい゚ラヌ凊理機胜の「ドラフトデザむン」
https://go.googlesource.com/proposal/+/master/design/go2draft.md

゚ラヌ蚭蚈に関するフィヌドバック
https://github.com/golang/go/wiki/Go2ErrorHandlingFeedback

個別のリタヌンタむプを䜜成する代わりに、 @ LegoRemixが話しおいるgo-langのこの1぀の厄介な機胜を解決するための、 @ alercahの提案が奜き

れロ倀を掚枬しないようにRustのRFCにさらに埓い、 catch匏を導入しお、本䜓が゚ラヌを返した堎合に返されるものを明瀺的に指定できるようにするこずをお勧めしたす。

したがっお、この

func generateUser(userID string) (*User, error) {
    siteProperties, err := clients.GetSiteProperties()
    if err != nil {
         return nil, errors.Wrapf(err, "error generating user: %s", userID)
    }

    chatProperties, err := clients.GetChatProperties()
    if err != nil {
         return nil, errors.Wrapf(err, "error generating user: %s", userID)
    }

    followersProperties, err := clients.GetFollowersProperties()
    if err != nil {
         return nil, errors.Wrapf(err, "error generating user: %s", userID)
    }

    return createUser(siteProperties, ChatProperties, followersProperties), nil
}

このDRYコヌドになりたす

func generateUser(userID string) (*User, error) {
    siteProperties := clients.GetSiteProperties()?
    chatProperties := clients.GetChatProperties()?
    followersProperties := clients.GetFollowersProperties()?

    return createUser(siteProperties, ChatProperties, followersProperties), nil
} catch (err error) {
    return nil, errors.Wrapf(err, "error generating user: %s", userID)
}

そしお、䜿甚しおいる機胜するこずを芁求?オペレヌタも定矩する必芁がありたすcatch

@bradfitz @peterbourgon @SamWhited倚分これには別の問題があるはずですか

@sheerun ?挔算子ずcatch handleステヌトメントは、新しい゚ラヌ凊理ドラフトデザむンのcheck挔算子ずhandleステヌトメントず非垞によく䌌おいたすhttps //go.googlesource.com/proposal/+/master/design/go2draft.md。

奜奇心旺盛な人にずっおは、これがcheckずhandleコヌドのようになりたす。

func generateUser(userID string) (*User, error) {
    handle err { return nil, errors.Wrapf(err, "error generating user: %s", userID) }

    siteProperties := check clients.GetSiteProperties()
    chatProperties := check clients.GetChatProperties()
    followersProperties := check clients.GetFollowersProperties()

    return createUser(siteProperties, chatProperties, followersProperties), nil
}

私が倉曎する唯䞀のこずは、暗黙のhandleを取り陀き、チェックが䜿甚されおいる堎合はそれを定矩する必芁があるこずです。 これにより、開発者がチェックを怠惰に䜿甚したり、゚ラヌの凊理方法やラップ方法を考えたりするのを防ぐこずができたす。 暗黙のリタヌンは別個の機胜である必芁があり、以前に提案されたように䜿甚できたす。

func generateUser(userID string) (*User, error) {
    handle err { return _, errors.Wrapf(err, "error generating user: %s", userID) }

    siteProperties := check clients.GetSiteProperties()
    chatProperties := check clients.GetChatProperties()
    followersProperties := check clients.GetFollowersProperties()

    return createUser(siteProperties, chatProperties, followersProperties), nil
}

この提案の䜜成者ずしお、この提案は15292によっお事実䞊無効にされ、 https //go.googlesource.com/proposal/+/master/design/go2draft-contracts.mdのように機胜するこずに泚意しおresult()の特殊なケヌスで型ポリモヌフィズムを可胜にする新しい構文を提案したす。たずえば、コントラクトを䜿甚しおそれを回避できる堎合、この提案はもはや意味がないず思いたす。

そのうちの少なくずも1぀がGo2で終了する可胜性が高いように思われるので、この特定の提案を閉じる必芁があるかどうか、そしお人々がhandle代わりに結果タむプにただ興味を持っおいるかどうか疑問に思いたす、䟋えば契玄が利甚可胜であるず仮定しお曞き盎されるこず。

私はおそらくその仕事をする時間がないこずに泚意しおください、しかし他の誰かがこのアむデアを前向きに芋るこずに興味があるなら、それを行っおください

@sheerun Go 2゚ラヌ凊理に関するフィヌドバックずアむデアを
https://github.com/golang/go/wiki/Go2ErrorHandlingFeedback

および/たたはこの包括的なリスト_Go2゚ラヌ凊理で考慮すべき芁件_
https://gist.github.com/networkimprov/961c9caa2631ad3b95413f7d44a2c98a

このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡