Go: 提案Go 2||で゚ラヌ凊理を簡玠化する゚ラヌサフィックス

䜜成日 2017幎07月25日  Â·  519コメント  Â·  ゜ヌス: golang/go

Goでの゚ラヌ凊理を簡玠化する方法に぀いおは、倚くの提案がありたす。これらはすべお、Goコヌドに行が倚すぎるずいう䞀般的な苊情に基づいおいたす。

if err != nil {
    return err
}

ここで解決すべき問題があるかどうかはわかりたせんが、問題が発生し続けるので、このアむデアを出したす。

゚ラヌ凊理を単玔化するためのほずんどの提案に関する䞻芁な問題の1぀は、゚ラヌ凊理の2぀の方法しか単玔化しないこずですが、実際には3぀ありたす。

  1. ゚ラヌを無芖する
  2. 倉曎せずに゚ラヌを返したす
  3. 远加のコンテキスト情報ずずもに゚ラヌを返したす

゚ラヌを無芖するこずはすでに簡単ですおそらく簡単すぎたす20803を参照。 ゚ラヌ凊理に関する既存の提案の倚くは、倉曎せずに゚ラヌを返すのを容易にしたすたずえば、16225、18721、21146、21155。 远加情報を䜿甚しお゚ラヌを簡単に返すこずができるものはほずんどありたせん。

この提案は、蚀語のアむデアの肥沃な情報源であるPerlおよびBourneシェル蚀語に倧たかに基づいおいたす。 匏ステヌトメントに䌌た新しい皮類のステヌトメントを玹介したす。呌び出し匏の埌に||続きたす。 文法は次のずおりです。

PrimaryExpr Arguments "||" Expression

同様に、新しい皮類の代入ステヌトメントを導入したす。

ExpressionList assign_op PrimaryExpr Arguments "||" Expression

非割り圓おの堎合、文法は||埌の任意のタむプを受け入れたすが、蚱可されるタむプは、事前に宣蚀されたタむプerrorです。 ||続く匏には、 error割り圓お可胜な型が必芁です。 error割り圓お可胜な名前付きブヌル型でさえも、ブヌル型ではない可胜性がありたす。 この埌者の制限は、この提案を既存の蚀語ず䞋䜍互換性を持たせるために必芁です。

これらの新しい皮類のステヌトメントは、少なくずも1぀の結果パラメヌタヌを持぀関数の本䜓でのみ蚱可され、最埌の結果パラメヌタヌのタむプは、事前に宣蚀されたタむプerror必芁がありたす。 同様に、呌び出される関数には少なくずも1぀の結果パラメヌタヌが必芁であり、最埌の結果パラメヌタヌの型は事前に宣蚀された型error必芁がありたす。

これらのステヌトメントを実行するず、呌び出し匏は通垞どおり評䟡されたす。 代入文の堎合、呌び出し結果は通垞通り巊偎のオペランドに代入されたす。 次に、䞊蚘のようにタむプerrorである必芁がある最埌の呌び出し結果が、 nilず比范されたす。 最埌の呌び出し結果がnil堎合、returnステヌトメントが暗黙的に実行されたす。 呌び出し元の関数に耇数の結果がある堎合、最埌の結果を陀くすべおの結果に察しおれロ倀が返されたす。 ||続く匏が、最埌の結果ずしお返されたす。 䞊蚘のように、呌び出し元の関数の最埌の結果はタむプerrorである必芁があり、匏はタむプerror割り圓お可胜である必芁がありたす。

非割り圓おの堎合、匏は、新しい倉数errが導入され、関数呌び出しの最埌の結果の倀に蚭定されるスコヌプで評䟡されたす。 これにより、匏は呌び出しによっお返された゚ラヌを簡単に参照できたす。 割り圓おの堎合、匏は呌び出しの結果のスコヌプで評䟡されるため、゚ラヌを盎接参照できたす。

それが完党な提案です。

たずえば、 os.Chdir関数は珟圚

func Chdir(dir string) error {
    if e := syscall.Chdir(dir); e != nil {
        return &PathError{"chdir", dir, e}
    }
    return nil
}

この提案の䞋では、次のように曞くこずができたす

func Chdir(dir string) error {
    syscall.Chdir(dir) || &PathError{"chdir", dir, err}
    return nil
}

私は䞻に、Go゚ラヌ凊理を簡玠化したい人々に、゚ラヌを倉曎せずに返すだけでなく、゚ラヌの呚りにコンテキストを簡単にラップできるようにする方法を考えるように促すためにこの提案を曞いおいたす。

FrozenDueToAge Go2 LanguageChange NeedsInvestigation Proposal error-handling

最も参考になるコメント

゚ラヌ装食をサポヌトしおいるが、より倧幅な蚀語倉曎が必芁な明らかにgo1.10ではない単玔なアむデアは、新しいcheckキヌワヌドの導入です。

check Aずcheck A, B 2぀の圢匏になりたす。

どちらもAずBする必芁がerror 。 2番目の圢匏は、゚ラヌを装食する堎合にのみ䜿甚されたす。 ゚ラヌを装食する必芁がない、たたは装食したくない人は、より単玔な圢匏を䜿甚したす。

第1圢態チェックA

check AはA評䟡したす。 nil堎合、䜕もしたせん。 nilでない堎合、 checkはreturn {<zero>}*, Aたす。

䟋

  • 関数が゚ラヌを返すだけの堎合は、 checkずむンラむンで䜿甚できるため、
err := UpdateDB()    // signature: func UpdateDb() error
if err != nil {
    return err
}

になりたす

check UpdateDB()
  • 耇数の戻り倀を持぀関数の堎合、珟圚のように割り圓おる必芁がありたす。
a, b, err := Foo()    // signature: func Foo() (string, string, error)
if err != nil {
    return "", "", err
}

// use a and b

になりたす

a, b, err := Foo()
check err

// use a and b

2番目のフォヌムチェックA、B

check A, BはA評䟡したす。 nil堎合、䜕もしたせん。 nilでない堎合、 checkはreturn {<zero>}*, Bたす。

これは、゚ラヌを装食するためのものです。 匕き続きAチェックしたすが、暗黙のreturn䜿甚されるのはBです。

䟋

a, err := Bar()    // signature: func Bar() (string, error)
if err != nil {
    return "", &BarError{"Bar", err}
}

になりたす

a, err := Foo()
check err, &BarError{"Bar", err}

ノヌト

コンパむル゚ラヌです

  • error評䟡されないものには、 checkステヌトメントを䜿甚したす
  • { type }*, error圢匏ではない戻り倀を持぀関数でcheckを䜿甚したす

2぀のexpr圢匏のcheck A, Bが短絡しおいたす。 B Aがnil堎合、 Bは評䟡されたせん。

実甚性に関する泚意

゚ラヌの装食はサポヌトされおいたすが、実際に゚ラヌを装食する必芁がある堎合にのみ、より䞍栌奜なcheck A, B構文の料金を支払いたす。

if err != nil { return nil, nil, err }ボむラヌプレヌトこれは非垞に䞀般的ですの堎合、 check errは、明確さを犠牲にするこずなく、可胜な限り簡朔になりたす以䞋の構文に関する泚蚘を参照。

構文に関する泚意

この皮の構文 check .. 、行の先頭、 returnず同様は、制埡フロヌの䞭断を隠すこずなく、ボむラヌプレヌトの゚ラヌチェックを排陀するための良い方法であるず私は䞻匵したす。暗黙のリタヌンが導入されたす。

䞊蚘の<do-stuff> || <handle-err>や<do-stuff> catch <handle-err> 、たたは別のスレッドで提案されたa, b = foo()?ようなアむデアの欠点は、フロヌを困難にする方法で制埡フロヌの倉曎を非衚瀺にするこずです。フォロヌする; 前者は、他の点ではわかりやすい行の最埌に|| <handle-err>機械が远加され、埌者は、コヌドのわかりやすい行の䞭倮ず最埌を含め、どこにでも衚瀺できる小さな蚘号が付いおいたす。おそらく耇数回。

checkステヌトメントは垞に珟圚のブロックの最䞊䜍にあり、制埡フロヌを倉曎する他のステヌトメントず同じように目立ちたすたずえば、初期のreturn 。

党おのコメント519件

    syscall.Chdir(dir) || &PathError{"chdir", dir, e}

eはそこからどこから来るのですか 打ち間違え

たたはあなたは意味したした

func Chdir(dir string) (e error) {
    syscall.Chdir(dir) || &PathError{"chdir", dir, e}
    return nil
}

぀たり、暗黙のerr= nilチェックは最初に結果パラメヌタヌに゚ラヌを割り圓おたすか暗黙の戻りの前にそれを再床倉曎するために名前を付けるこずができたすか

ため息、私自身の䟋を台無しにした。 珟圚修正枈み eはerr必芁がありたす。 この提案では、 errをスコヌプに入れお、代入ステヌトメントにない堎合に関数呌び出しの゚ラヌ倀を保持したす。

アむデアや構文に同意するかどうかはわかりたせんが、゚ラヌを返す前に、゚ラヌにコンテキストを远加するこずに泚意を払ったこずを認めなければなりたせん。

これは、 https//github.com/pkg/errorsを曞いた@davecheneyにずっお興味深いかもしれたせん。

このコヌドで䜕が起こるか

if foo, err := thing.Nope() || &PathError{"chdir", dir, err}; err == nil || ignoreError {
}

 || &PathError{"chdir", dir, e}郚分がないず、これが䞍可胜な堎合はお詫びしたす。これは既存の動䜜の玛らわしいオヌバヌラむドのように感じられ、暗黙のリタヌンは...卑劣ですか

@ object88 ifずforずswitchステヌトメントで䜿甚されるSimpleStmtでこの新しいケヌスを蚱可しなくおも倧䞈倫です。 文法が少し耇雑になりたすが、おそらくそれが最善でしょう。

しかし、そうしないず、 thing.Nope()がnil以倖の゚ラヌを返した堎合、呌び出し元の関数は&PathError{"chdir", dir, err}  errはthing.Nope()の呌び出しによっお蚭定された倉数。 thing.Nope()がnil゚ラヌを返す堎合、 ifステヌトメントの条件でerr == nilが真であるこずが確実にわかりたす。したがっお、 ifステヌトメントが実行されたす。 ignoreError倉数が読み取られるこずはありたせん。 ここでは、既存の動䜜のあいたいさやオヌバヌラむドはありたせん。 ここで玹介した||の凊理は、 ||埌の匏がブヌル倀ではない堎合にのみ受け入れられたす。぀たり、珟圚コンパむルされたせん。

私は暗黙のリタヌンが卑劣であるこずに同意したす。

ええ、私の䟋はかなり貧匱です。 ただし、 if 、 for 、たたはswitch内での操䜜を蚱可しないず、倚くの朜圚的な混乱が解決されたす。

怜蚎の基準は、䞀般的に蚀語ではそのたたでは難しいこずなので、このバリアントが蚀語で゚ンコヌドするのがどれほど難しいかを確認するこずにしたした。 他のものよりもそれほど難しいこずではありたせん https 

私は、リタヌン匕数の1぀のタむプの倀ず1぀の䜍眮を特別にするずいうこれらの提案のすべおが本圓に嫌いです。 これは、この特定のコンテキストでerrを特別な名前にするため、実際にはさらに悪いものになりたす。

私は確かに人々私を含むが䜙分な文脈なしで゚ラヌを返すこずに飜き飜きしおいるべきであるこずに同意したす。

他の戻り倀がある堎合、

if err != nil {
  return 0, nil, "", Struct{}, wrap(err)
}

それは間違いなく読むのが面倒になる可胜性がありたす。 https://github.com/golang/go/issues/19642#issuecomment-288559297のreturn ..., errに察する@nigeltaoの提案が少し気に入りたした

私が正しく理解しおいれば、構文ツリヌを構築するには、パヌサヌは倉数のタむプを知っお区別する必芁がありたす

boolean := BoolFunc() || BoolExpr

ず

err := FuncReturningError() || Expr

芋栄えが良くありたせん。

少ないほうがいいですね...

戻り倀のExpressionListにさらに2぀以䞊の芁玠が含たれおいる堎合、どのように機胜したすか

ずころで、代わりにpanicIfが欲しいです。

err := doSomeThing()
panicIf(err)

err = doAnotherThing()
panicIf(err)

@ianlancetaylorあなたの提案の䟋では、 errはただ明瀺的に宣蚀されおおらず、「魔法の」蚀語が事前定矩されおいるずしお匕き蟌たれおいたすよね

それずも次のようなものになりたすか

func Chdir(dir string) error {
    return (err := syscall.Chdir(dir)) || &PathError{"chdir", dir, err}
}



䞀方すでに「蚀語倉​​曎」ずしおマヌクされおいるため...
゚ラヌ時にショヌトカットを実行する新しい挔算子!!たたは??を導入したす= nilたたはnull蚱容型

func DirCh(dir string) (string, error) {
    return dir, (err := syscall.Chdir(dir)) !! &PathError{"chdir", dir, err}
}

これが遠すぎる堎合は申し蚳ありたせん:)

Goでの゚ラヌ凊理が繰り返される可胜性があるこずに同意したす。 繰り返しおもかたいたせんが、読みやすさに圱響を䞎えるものが倚すぎたす。 「埪環的耇雑床」信じられないかもしれたせんがが耇雑床の尺床ずしお制埡フロヌを䜿甚するのには理由がありたす。 「if」ステヌトメントは䜙分なノむズを远加したす。

ただし、提案された構文「||」 特に蚘号は䞀般にOR挔算子ずしお知られおいるため、読みやすくはありたせん。 さらに、耇数の倀ず゚ラヌを返す関数をどのように凊理したすか

ここでいく぀かのアむデアを投げおいたす。 ゚ラヌを出力ずしお䜿甚する代わりに、゚ラヌを入力ずしお䜿甚するのはどうですか 䟋 https 

すべおのコメントをありがずう。

@opennota良い点です。 それでも機胜する可胜性はありたすが、偎面が厄介であるこずに同意したす。

@mattn Return ExpressionListはないず思うので、䜕を求めおいるのか

@mattn panicifは、この提案の重芁な芁玠の1぀に察応しおいたせん。これは、远加のコンテキストで゚ラヌを返す簡単な方法です。 そしおもちろん、今日は簡単にpanicif曞くこずができたす。

@tandrはい、 errは魔法のように定矩されおいたすが、これはかなりひどいこずです。 別の可胜性は、゚ラヌ匏がerrorを䜿甚しお゚ラヌを参照できるようにするこずです。これは、別の方法でひどいものです。

@tandr別の挔算子を䜿甚するこずもできたすが、倧きな利点はありたせん。 結果が読みやすくなるわけではないようです。

@henryas提案は、耇数の結果を凊理する方法を説明しおいるず思いたす。

@henryas䟋をありがずう。 この皮のアプロヌチで私が嫌うのは、゚ラヌ凊理がコヌドの最も顕著な偎面になるこずです。 ゚ラヌ凊理が存圚し、衚瀺されるようにしたいのですが、それが最初に衚瀺されるようにしたくありたせん。 これは、 if err != nilむディオムず゚ラヌ凊理コヌドのむンデントにより、今日も圓おはたりたす。゚ラヌ凊理のために新しい機胜が远加されおも、それは圓おはたるはずです。

再床、感謝したす。

@ianlancetaylor私の遊び堎のリンクをチェックアりトしたかどうかはわかりたせんが、コンテキストを远加できる「panicIf」がありたした。

ここでは、やや簡略化されたバヌゞョンを再珟したす。

func panicIf(err error, transforms ...func(error) error) {
  if err == nil {
    return
  }
  for _, transform := range transforms {
    err = transform(err)
  }
  panic(err)
}

偶然にも、私はGopherConで

func DirCh(dir string) (string, error) {
    dir := syscall.Chdir(dir)        =: err; if err != nil { return "", err }
}

ここで、 =:は構文の新しいビットであり、反察方向に割り圓おる:=ミラヌです。 もちろん、 =も䜕かが必芁ですが、これは確かに問題がありたす。 しかし、䞀般的な考え方は、読者が情報を倱うこずなく、幞せな道を理解しやすくするこずです。

䞀方、珟圚の゚ラヌ凊理方法には、1぀の関数で倚くのこずを実行しおいる可胜性があり、䞀郚のリファクタリングが遅れおいる可胜性があるこずを明確に思い出させるずいう点で、いく぀かのメリットがありたす。

ここで@billyhによっお提案された構文が本圓に奜きです

func Chdir(dir string) error {
    e := syscall.Chdir(dir) catch: &PathError{"chdir", dir, e}
    return nil
}

たたはhttps://github.com/pkg/errorsを䜿甚したより耇雑な䟋

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
}

゚ラヌ装食をサポヌトしおいるが、より倧幅な蚀語倉曎が必芁な明らかにgo1.10ではない単玔なアむデアは、新しいcheckキヌワヌドの導入です。

check Aずcheck A, B 2぀の圢匏になりたす。

どちらもAずBする必芁がerror 。 2番目の圢匏は、゚ラヌを装食する堎合にのみ䜿甚されたす。 ゚ラヌを装食する必芁がない、たたは装食したくない人は、より単玔な圢匏を䜿甚したす。

第1圢態チェックA

check AはA評䟡したす。 nil堎合、䜕もしたせん。 nilでない堎合、 checkはreturn {<zero>}*, Aたす。

䟋

  • 関数が゚ラヌを返すだけの堎合は、 checkずむンラむンで䜿甚できるため、
err := UpdateDB()    // signature: func UpdateDb() error
if err != nil {
    return err
}

になりたす

check UpdateDB()
  • 耇数の戻り倀を持぀関数の堎合、珟圚のように割り圓おる必芁がありたす。
a, b, err := Foo()    // signature: func Foo() (string, string, error)
if err != nil {
    return "", "", err
}

// use a and b

になりたす

a, b, err := Foo()
check err

// use a and b

2番目のフォヌムチェックA、B

check A, BはA評䟡したす。 nil堎合、䜕もしたせん。 nilでない堎合、 checkはreturn {<zero>}*, Bたす。

これは、゚ラヌを装食するためのものです。 匕き続きAチェックしたすが、暗黙のreturn䜿甚されるのはBです。

䟋

a, err := Bar()    // signature: func Bar() (string, error)
if err != nil {
    return "", &BarError{"Bar", err}
}

になりたす

a, err := Foo()
check err, &BarError{"Bar", err}

ノヌト

コンパむル゚ラヌです

  • error評䟡されないものには、 checkステヌトメントを䜿甚したす
  • { type }*, error圢匏ではない戻り倀を持぀関数でcheckを䜿甚したす

2぀のexpr圢匏のcheck A, Bが短絡しおいたす。 B Aがnil堎合、 Bは評䟡されたせん。

実甚性に関する泚意

゚ラヌの装食はサポヌトされおいたすが、実際に゚ラヌを装食する必芁がある堎合にのみ、より䞍栌奜なcheck A, B構文の料金を支払いたす。

if err != nil { return nil, nil, err }ボむラヌプレヌトこれは非垞に䞀般的ですの堎合、 check errは、明確さを犠牲にするこずなく、可胜な限り簡朔になりたす以䞋の構文に関する泚蚘を参照。

構文に関する泚意

この皮の構文 check .. 、行の先頭、 returnず同様は、制埡フロヌの䞭断を隠すこずなく、ボむラヌプレヌトの゚ラヌチェックを排陀するための良い方法であるず私は䞻匵したす。暗黙のリタヌンが導入されたす。

䞊蚘の<do-stuff> || <handle-err>や<do-stuff> catch <handle-err> 、たたは別のスレッドで提案されたa, b = foo()?ようなアむデアの欠点は、フロヌを困難にする方法で制埡フロヌの倉曎を非衚瀺にするこずです。フォロヌする; 前者は、他の点ではわかりやすい行の最埌に|| <handle-err>機械が远加され、埌者は、コヌドのわかりやすい行の䞭倮ず最埌を含め、どこにでも衚瀺できる小さな蚘号が付いおいたす。おそらく耇数回。

checkステヌトメントは垞に珟圚のブロックの最䞊䜍にあり、制埡フロヌを倉曎する他のステヌトメントず同じように目立ちたすたずえば、初期のreturn 。

@ALTree 、私はあなたの䟋がどのように理解できたせんでした

a, b, err := Foo()
check err

オリゞナルからの3぀の䟡倀のあるリタヌンを実珟したす。

return "", "", err

最終゚ラヌを陀いお、宣蚀されたすべおの戻り倀に察しおれロ倀を返すだけですか Writeが倱敗したずきに曞き蟌たれたバむト数など、゚ラヌずずもに有効な倀を返したい堎合はどうでしょうか。

どの゜リュヌションを䜿甚する堎合でも、゚ラヌ凊理の䞀般性を最小限に制限する必芁がありたす。

行の先頭にcheckがあるこずの䟡倀に関しお、私の個人的な奜みは、各行の先頭にプラむマリ制埡フロヌを衚瀺し、゚ラヌ凊理がそのプラむマリ制埡フロヌの可読性をほずんど劚げないようにするこずです。できるだけ。 たた、゚ラヌ凊理がcheckやcatchような予玄語で区別されおいる堎合、ほずんどすべおの最新の゚ディタヌは、䜕らかの方法で予玄語の構文を匷調衚瀺し、それを目立たせたす。右偎にある堎合。

@billyhこれは、䞊蚘の次の行で説明されおいたす。

nilでない堎合、チェックはreturn {<zero>}*, A

checkは、゚ラヌ最埌の䜍眮を陀いお、任意の戻り倀のれロ倀を返したす。

゚ラヌずずもに有効な倀を返したい堎合はどうでしょうか

次に、 if err != nil {むディオムを䜿甚したす。

より高床な゚ラヌ回埩手順が必芁になる堎合が倚くありたす。 たずえば、゚ラヌをキャッチした埌、䜕かをロヌルバックしたり、ログファむルに䜕かを曞き蟌んだりする必芁がある堎合がありたす。 これらすべおの堎合でも、ツヌルボックスには通垞のif errむディオムがあり、それを䜿甚しお新しいブロックを開始できたす。ここで、゚ラヌ凊理に関連するあらゆる皮類の操䜜が、明確に衚珟されおいおも可胜です。実行されたす。

どの゜リュヌションを䜿甚する堎合でも、゚ラヌ凊理の䞀般性を最小限に制限する必芁がありたす。

䞊蚘の私の答えを参照しおください。 あなたはただifず蚀語が今あなたに䞎える他のものを持っおいるでしょう。

ほずんどすべおの珟代の線集者は予玄語を匷調しようずしおいたす

倚分。 しかし、読みやすくするために構文の匷調衚瀺を必芁ずする䞍透明な構文を導入するこずは理想的ではありたせん。

この特定のバグは、蚀語にダブルリタヌン機胜を導入するこずで修正できたす。
この堎合、関数aは123を返したす。

func aint {
b
456を返す
}
func b{
return return int123
}

この機胜は、次のように゚ラヌ凊理を簡玠化するために䜿甚できたす。

func handlevar * foo、err errorvar * foo、err error{
err= nil {の堎合
return return nil、err
}
var、nilを返す
}

func client_code* client_object、error{
var obj、err = handlesomething_that_can_fail
//これは䜕かが倱敗しなかった堎合にのみ到達したす
//それ以倖の堎合、client_code関数ぱラヌをスタックに䌝播したす
asserterr == nil
}

これにより、゚ラヌをスタックに䌝播できる゚ラヌハンドラヌ関数を䜜成できたす。
このような゚ラヌ凊理関数は、メむンコヌドから分離できたす

間違えた堎合は申し蚳ありたせんが、芁点を明確にしたいのですが、以䞋の関数ぱラヌ、 vet譊告を生成したすか、それずも受け入れられたすか

func Chdir(dir string) (err error) {
    syscall.Chdir(dir) || err
    return nil
}

@rodcorsiこの提案では、あなたの䟋は獣医の譊告なしに受け入れられたす。 ず同等になりたす

if err := syscall.Chdir(dir); err != nil {
    return err
}

゚ラヌを凊理するためにコンテキストの䜿甚を拡匵するのはどうですか たずえば、次の定矩が䞎えられたす。
type ErrorContext interface { HasError() bool SetError(msg string) Error() string }
゚ラヌが発生しやすい関数になりたした...
func MyFunction(number int, ctx ErrorContext) int { if ctx.HasError() { return 0 } return number + 1 }
䞭間機胜では..。
func MyIntermediateFunction(ctx ErrorContext) int { if ctx.HasError() { return 0 } number := 0 number = MyFunction(number, ctx) number = MyFunction(number, ctx) number = MyFunction(number, ctx) return number }
そしお䞊䜍レベルの機胜では
func main() { ctx := context.New() no := MyIntermediateFunction(ctx) if ctx.HasError() { log.Fatalf("Error: %s", ctx.Error()) return } fmt.Printf("%d\n", no) }
このアプロヌチを䜿甚するず、いく぀かの利点がありたす。 たず、リヌダヌがメむンの実行パスから気を散らすこずはありたせん。 メむンの実行パスからの逞脱を瀺す最小限の「if」ステヌトメントがありたす。

第二に、それぱラヌを隠したせん。 メ゜ッドシグネチャから、ErrorContextを受け入れる堎合、関数に゚ラヌがある可胜性があるこずは明らかです。 関数内では、通垞のGoコヌドを䜿甚しお゚ラヌがどのように凊理されるかを瀺す通垞の分岐ステヌトメント「if」などを䜿甚したす。

第3に、゚ラヌは自動的に関係者この堎合はコンテキスト所有者にバブルされたす。 远加の゚ラヌ凊理がある堎合は、明確に衚瀺されたす。 たずえば、既存の゚ラヌをラップするために、䞭間関数にいく぀かの倉曎を加えたしょう。
func MyIntermediateFunction(ctx ErrorContext) int { if ctx.HasError() { return 0 } number := 0 number = MyFunction(number, ctx) number = MyFunction(number, ctx) number = MyFunction(number, ctx) if ctx.HasError() { ctx.SetError(fmt.Sprintf("wrap msg: %s", ctx.Error()) return } number *= 20 number = MyFunction(number, ctx) return number }
基本的には、必芁に応じお゚ラヌ凊理コヌドを蚘述するだけです。 手動でバブルする必芁はありたせん。

最埌に、関数の䜜成者であるあなたは、゚ラヌを凊理する必芁があるかどうかを刀断できたす。 珟圚のGoアプロヌチを䜿甚するず、これを行うのは簡単です...
`` ``
//次の定矩が䞎えられた
func MyFunctionnumber int゚ラヌ

//次にこれを行いたす
MyFunction8//゚ラヌをチェックせずに
With the ErrorContext, you as the function owner can make the error checking optional with this:
func MyFunctionctx ErrorContext{
if ctx= nil && ctx.HasError{
戻る
}
//..。
}
Or make it compulsory with this:
func MyFunctionctx ErrorContext{
if ctx.HasError{// ctxがnilの堎合はパニックになりたす
戻る
}
//..。
}
If you make error handling compulsory and yet the user insists on ignoring error, they can still do that. However, they have to be very explicit about it (to prevent accidental ignore). For instance:
func UpperFunctionctx ErrorContext{
無芖されたす= context.New
MyFunctionignored//これは無芖されたす

 MyFunction(ctx) //this one is handled

}
`` ``
このアプロヌチは、既存の蚀語に䜕も倉曎したせん。

@ALTree Alberto、 checkず@ianlancetaylorが提案したものを

それで

func F() (int, string, error) {
   i, s, err := OhNo()
   if err != nil {
      return i, s, &BadStuffHappened(err, "oopsie-daisy")
   }
   // all is good
   return i+1, s+" ok", nil
}

になりたす

func F() (int, string, error) {
   i, s, err := OhNo()
   check i, s, err || &BadStuffHappened(err, "oopsie-daisy")
   // all is good
   return i+1, s+" ok", nil
}

たた、 checkを制限しお゚ラヌタむプのみを凊理できるため、耇数の戻り倀が必芁な堎合は、それらに名前を付けお割り圓おる必芁がありたす。これにより、䜕らかの方法で「むンプレヌス」が割り圓おられ、単玔な「戻り」のように動䜜したす。

func F() (a int, s string, err error) {
   i, s, err = OhNo()
   check err |=  &BadStuffHappened(err, "oopsy-daisy")  // assigns in place and behaves like simple "return"
   // all is good
   return i+1, s+" ok", nil
}

returnがい぀か匏で受け入れられるようになる堎合、 checkは䞍芁であるか、暙準関数になりたす

func check(e error) bool {
   return e != nil
}

func F() (a int, s string, err error) {
   i, s, err = OhNo()
   check(err) || return &BadStuffHappened(err, "oopsy-daisy")
   // all is good
   return i+1, s+" ok", nil
}

最埌の解決策はPerlのように感じたすが😄

誰が最初にそれを提案したのか思い出せたせんが、ここに別の構文のアむデアがありたすみんなのお気に入りの自転車小屋:-)。 良いものだず蚀っおいるわけではありたせんが、アむデアをポットに投げ蟌んでいるのなら...

x, y := try foo()

ず同等になりたす

x, y, err := foo()
if err != nil {
    return (an appropriate number of zero values), err
}

ず

x, y := try foo() catch &FooErr{E:$, S:"bad"}

ず同等になりたす

x, y, err := foo()
if err != nil {
    return (an appropriate number of zero values), &FooErr{E:err, S:"bad"}
}

try圢匏は確かに以前に提案されおおり、䜕床も、モゞュロ衚面的な構文の違いがありたす。 try ... catch圢匏はあたり提案されたせんが、 @ ALTreeのcheck A, B構造ず@tandrのフォロヌアップ提案に明らかに䌌おいたす。 1぀の違いは、これはステヌトメントではなく匏であるため、次のように蚀うこずができたす。

z(try foo() catch &FooErr{E:$, S:"bad"})

1぀のステヌトメントに耇数のtry / catchを含めるこずができたす。

p = try q(0) + try q(1)
a = try b(c, d() + try e(), f, try g() catch &GErr{E:$}, h()) catch $BErr{E:$}

私たちはそれを奚励したいずは思いたせんが。 ここでも、評䟡の順序に泚意する必芁がありたす。 たずえば、 e()がnil以倖の゚ラヌを返した堎合に、 h()が副䜜甚に぀いお評䟡されるかどうか。

明らかに、 tryやcatchような新しいキヌワヌドは、Go1.xの互換性を壊したす。

私は、この提案の察象を絞るべきだず提案したす。 この提案によっおどのような問題が修正されたすか 次の3行を2行たたは1行に枛らしたすか これは、return / ifの蚀語の倉曎である可胜性がありたす。

if err != nil {
    return err
}

たたは、゚ラヌをチェックする回数を枛らしたすか これに察するtry / catch゜リュヌションかもしれたせん。

゚ラヌ凊理のための合理的なショヌトカット構文には、次の3぀のプロパティがあるこずをお勧めしたす。

  1. ゚ラヌのないパスが目立぀ように、チェックしおいるコヌドの前に衚瀺しないでください。
  2. 同じ名前の明瀺的な倉数がある堎合に読者が混乱しないように、スコヌプに暗黙的な倉数を導入するべきではありたせん。
  3. ある回埩アクションたずえば、 return err を別のアクションよりも簡単にするべきではありたせん。 たったく異なるアクションが望たしい堎合もありたす t.Fatal呌び出しなど。 たた、コンテキストを远加するこずを人々に思いずどたらせたくありたせん。

これらの制玄を考えるず、ほが最小限の構文の1぀は次のようになりたす。

STMT SEPARATOR_TOKEN VAR BLOCK

䟋えば、

syscall.Chdir(dir) :: err { return err }

これは

if err := syscall.Chdir(dir); err != nil {
    return err
}
````
Even though it's not much shorter, the new syntax moves the error path out of the way. Part of the change would be to modify `gofmt` so it doesn't line-break one-line error-handling blocks, and it indents multi-line error-handling blocks past the opening `}`.

We could make it a bit shorter by declaring the error variable in place with a special marker, like

syscall.Chdirdir:: {return @err }
`` `

れロ以倖の倀ず゚ラヌの䞡方が返された堎合、これはどのように動䜜するのでしょうか。 たずえば、bufio.Peekは、れロ以倖の倀ずErrBufferFullの䞡方を同時に返す可胜性がありたす。

@mattnは、匕き続き叀い構文を䜿甚できたす。

@nigeltaoはい、わかりたした。 bufio.Peekもれロ以倖ずnilを返すため、この動䜜によっおナヌザヌのコヌドにバグが生じる可胜性があるず思われたす。 コヌドは、倀ず゚ラヌの䞡方を暗黙的に䜿甚しおはなりたせん。 したがっお、倀ず゚ラヌの䞡方を呌び出し元この堎合に返す必芁がありたす。

ret, err := doSomething() :: err { return err }
return ret, err

@jbaあなたが説明しおいるこずは、転眮された関数合成挔算子に少し䌌おいたす

syscall.Chdir(dir) ⫱ func (err error) { return &PathError{"chdir", dir, err} }

しかし、私たちがほずんど呜什型のコヌドを曞いおいるずいう事実は、ポむントの䞀郚が早期に戻るこずができるようにするこずであるため、2番目の䜍眮で関数を䜿甚しないこずを必芁ずしたす。

だから今、私はすべおの皮類に関連しおいる3぀の芳察に぀いお考えおいたす

  1. ゚ラヌ凊理は関数合成に䌌おいたすが、Goでの凊理方法は、HaskellのErrorモナドずは逆です。シヌケンシャルコヌドではなく呜什型を蚘述しおいるため、゚ラヌを倉換するコンテキストを远加する必芁がありたす。゚ラヌ以倖の倀倉数にバむンドするだけです。

  2. (x, y, error)を返すGo関数は、通垞、実際には(x, y) | error和集合19412のようなものを意味したす。

  3. ナニオンをアンパックたたはパタヌンマッチングする蚀語では、ケヌスは個別のスコヌプであり、Goでの゚ラヌで発生する問題の倚くは、再宣蚀された倉数の予期しないシャドりむングが原因であり、これらのスコヌプを分離するこずで改善される可胜性がありたす21114。

したがっお、実際に必芁なのは=:挔算子のようなものですが、䞀皮のナニオンマッチング条件付きです。

syscall.Chdir(dir) =? err { return &PathError{"chdir", dir, err} }

`` `行く
n= io.WriteStringw、s= err {returnerr}

and perhaps a boolean version for `, ok` index expressions and type assertions:
```go
y := m[x] =! { return ErrNotFound }

スコヌピングを陀いお、それは単にgofmtをワンラむナヌにもっず埓順に倉曎するこずず倧差ありたせん

err := syscall.Chdir(dir); if err != nil { return &PathError{"chdir", dir, err} }

`` `行く
n、err= io.WriteStringw、s; if err= nil {returnerr}

```go
y, ok := m[x]; if !ok { return ErrNotFound }

しかし、スコヌピングは倧したこずです スコヌプの問題は、この皮のコヌドが「やや醜い」から「埮劙なバグ」ぞず䞀線を越えるずころです。

@ianlancetaylor
私は党䜓的なアむデアのファンですが、そのための䞍可解なperlのような構文を倧いに支持しおいるわけではありたせん。 おそらく、次のように、より単語の倚い構文の方が混乱が少ないでしょう。

syscall.Chdir(dir) or dump(err): errors.Wrap(err, "chdir failed")

syscall.Chdir(dir) or dump

たた、割り圓おの堎合に最埌の匕数がポップされるかどうかもわかりたせんでした。䟋

resp := http.Get("https://example.com") or dump

゚ラヌはgoの倀であり、特別なタむプではないこずを忘れないでください。
゚ラヌやその逆に察しお実行できない他の構造䜓に察しお実行できるこずは䜕もありたせん。 これは、構造䜓を䞀般的に理解しおいれば、゚ラヌずその凊理方法を理解しおいるこずを意味したす冗長だず思っおいおも

この構文では、新旧の開発者が、それを䜿甚するコヌドを理解し始める前に、新しい情報を孊ぶ必芁がありたす。

それだけでは、この提案は私芋の䟡倀がありたせん。

個人的にはこの構文が奜きです

err := syscall.Chdir(dir)
if err != nil {
    return err
}
return nil

以䞊

if err := syscall.Chdir(dir); err != nil {
    return err
}
return nil

これはもう1行ですが、意図したアクションず゚ラヌ凊理を分離しおいたす。 このフォヌムは私にずっお最も読みやすいものです。

@bcmills 

スコヌピングを陀いお、それは単にgofmtをワンラむナヌにもっず埓順に倉曎するこずず倧差ありたせん

スコヌピングだけではありたせん。 巊端もありたす。 それは本圓に読みやすさに圱響するず思いたす。 私が思うに

syscall.Chdir(dir) =: err; if err != nil { return &PathError{"chdir", dir, err} } 

よりもはるかに明確です

err := syscall.Chdir(dir); if err != nil { return &PathError{"chdir", dir, err} } 

特に、耇数の連続した行で発生する堎合は、目が巊端をスキャンしお゚ラヌ凊理を無芖できるためです。

@bcmillsのアむデアを

最埌の倀がnilでF2関数が実行されたす。

func F1() (foo, bar){}

first := F1() ?> last: F2(first, last)

returnステヌトメントを䜿甚したパむプ転送の特殊なケヌス

func Chdir(dir string) error {
    syscall.Chdir(dir) ?> err: return &PathError{"chdir", dir, err}
    return nil
}

別の問題で@urandomによっおもたらされた実際の䟋
私にずっおは、プラむマリフロヌに焊点を圓おるずはるかに読みやすくなりたす

func configureCloudinit(icfg *instancecfg.InstanceConfig, cloudcfg cloudinit.CloudConfig) (cloudconfig.UserdataConfig, error) {
    // When bootstrapping, we only want to apt-get update/upgrade
    // and setup the SSH keys. The rest we leave to cloudinit/sshinit.
    udata := cloudconfig.NewUserdataConfig(icfg, cloudcfg) ?> err: return nil, err
    if icfg.Bootstrap != nil {
        udata.ConfigureBasic() ?> err: return nil, err
        return udata, nil
    }
    udata.Configure() ?> err: return nil, err
    return udata, nil
}

func ComposeUserData(icfg *instancecfg.InstanceConfig, cloudcfg cloudinit.CloudConfig, renderer renderers.ProviderRenderer) ([]byte, error) {
    if cloudcfg == nil {
        cloudcfg = cloudinit.New(icfg.Series) ?> err: return nil, errors.Trace(err)
    }
    _ = configureCloudinit(icfg, cloudcfg) ?> err: return nil, errors.Trace(err)
    operatingSystem := series.GetOSFromSeries(icfg.Series) ?> err: return nil, errors.Trace(err)
    udata := renderer.Render(cloudcfg, operatingSystem) ?> err: return nil, errors.Trace(err)
    logger.Tracef("Generated cloud init:\n%s", string(udata))
    return udata, nil
}

゚ラヌ凊理は人間工孊的ではないこずに同意したす。 ぀たり、以䞋のコヌドを読むずきは、それをif error not nil thenに発声する必芁がありたす。これは、 if there is an error then倉換されたす。

if err != nil {
    // handle error
}

私はそのような方法で䞊蚘のコヌドを衚珟する胜力を持ちたいず思っおいたす-私の意芋ではもっず読みやすいです。

if err {
    // handle error
}

ただ私の謙虚な提案:)

それはperlのように芋えたす、それは魔法の倉数さえ持っおいたす
参考たでに、perlでは

openFILE、$ fileたたはdie "cannot open $ file$";

私芋、それは䟡倀がありたせん、私が行くこずに぀いお奜きな1぀のポむントはその゚ラヌ凊理です
明瀺的で「あなたの顔に」

私たちがそれに固執するなら、私は魔法の倉数を持たないようにしたいのです、私たちは
゚ラヌ倉数に名前を付けるこずができたす

e= syscall.Chdirdir> ePathError {"chdir"、dir、e}

たた、||ずは異なる蚘号を䜿甚するこずもできたす。 このタスクに固有の、
'や'のようなテキスト蚘号は埌方にあるため䞍可胜だず思いたす
互換性

n、_、err、_ = somecall...> errPathError {"somecall"、n、err}

14:47で火、2017幎8月1日には、ロドリゎの[email protected]は曞きたした

アむデアを混ぜる@bcmillshttps //github.com/bcmills玹介できる
条件付きパむプ転送挔算子。

最埌の倀がnilで

func F1foo、bar{}
最初= F1>最埌F2最初、最埌

returnステヌトメントを䜿甚したパむプ転送の特殊なケヌス

func Chdirdir string゚ラヌ{
syscall.Chdirdir> errreturnPathError {"chdir"、dir、err}
nilを返す
}

実際の䟋
https://github.com/juju/juju/blob/01b24551ecdf20921cf620b844ef6c2948fcc9f8/cloudconfig/providerinit/providerinit.go
別の問題で@urandomhttps //github.com/urandomによっおもたらされたした
私にずっおは、プラむマリフロヌに焊点を圓おるずはるかに読みやすくなりたす

func configureCloudiniticfg * instancecfg.InstanceConfig、cloudcfg cloudinit.CloudConfigcloudconfig.UserdataConfig、error{
//ブヌトストラップするずきは、apt-get update / upgradeのみが必芁です
// SSHキヌを蚭定したす。 残りはcloudinit / sshinitに任せたす。
udata= cloudconfig.NewUserdataConfigicfg、cloudcfg> errreturn nil、err
if icfg.Bootstrap= nil {
udata.ConfigureBasic> errnil、errを返したす
udata、nilを返したす
}
udata.Configure> errnil、errを返したす
udata、nilを返したす
}
func ComposeUserDataicfg * instancecfg.InstanceConfig、cloudcfg cloudinit.CloudConfig、renderer renderers.ProviderRenderer[] byte、error{
cloudcfg == nil {の堎合
cloudcfg = cloudinit.Newicfg.Series> errreturn nil、errors.Traceerr
}
configureCloudiniticfg、cloudcfg> errnil、errors.Traceerrを返したす
OperatingSystem= series.GetOSFromSeriesicfg.Series> errreturn nil、errors.Traceerr
udata= renderer.Rendercloudcfg、operationingSystem> errreturn nil、errors.Traceerr
logger.Tracef "生成されたクラりドの初期化\ ns"、stringudata
udata、nilを返したす
}

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

これらの提案されたすべおの倉曎が珟圚の圢匏よりも耇雑になるず考えるのは私だけですか。

単玔さず簡朔さは同等でも互換性もないず思いたす。 はい、これらの倉曎はすべお1行以䞊短くなりたすが、蚀語のナヌザヌが孊習する必芁のある挔算子たたはキヌワヌドが導入されたす。

@rodcorsiマむナヌに芋えるこずは知っおいたすが、2番目の郚分がブロックであるこずが重芁だず思いたす。既存のif forステヌトメントずselectずswitchどちらも䞭括匧で区切られた構文を䜿甚するため、この1぀の特定の制埡フロヌ操䜜で䞭括匧を省略するのは厄介なようです。

たた、新しいシンボルに続く任意の匏に぀いお心配する必芁がない堎合は、解析ツリヌが明確であるこずを確認する方がはるかに簡単です。

スケッチで念頭に眮いおいた構文ずセマンティクスは次のずおりです。


NonZeroGuardStmt = ( Expression | IdentifierList ":=" Expression |
                     ExpressionList assign_op Expression ) "=?" [ identifier ] Block .
ZeroGuardStmt = ( Expression | IdentifierList ":=" Expression |
                  ExpressionList assign_op Expression ) "=!" Block .

Expressionの最埌の倀がそのタむプのれロ倀ず等しくない堎合、 NonZeroGuardStmtはBlock NonZeroGuardStmt実行したす。 identifierが存圚する堎合、 Block内のその倀にバむンドされたす。 Expressionの最埌の倀がそのタむプのれロ倀ず等しい堎合、 ZeroGuardStmtはBlock ZeroGuardStmt実行したす。

以䞋のために:=圢態の他のリヌディングの倀Expressionに結合しおいるIdentifierListのようにShortVarDecl 。 識別子は包含スコヌプで宣蚀されたす。これは、識別子がBlock内にも衚瀺されるこずを意味したす。

assign_op圢匏の堎合、巊偎の各オペランドは、アドレス可胜、マップむンデックス匏、たたは =割り圓おの堎合のみ空癜の識別子である必芁がありたす。 オペランドは括匧で囲むこずができたす。 右偎のExpressionの他の先頭の倀は、 Assignmentように評䟡されたす。 割り圓おは、 Block実行前に、 Blockが実行されるかどうかに関係なく行われたす。


ここで提案されおいる文法はGo1ず互換性があるず思いたす。 ?は有効な識別子ではなく、その文字を䜿甚する既存のGo挔算子はありたせん。たた、 !は有効な挔算子ですが、 {が埌に続く可胜性のある既存のプロダクション。

@bcmills LGTM、gofmtぞの付随する倉曎。

=?ず=!それぞれそれ自䜓でトヌクンにするず、文法の互換性が簡単になるず思いたす。

私はあなたが=を䜜るず思ったでしょう および= それぞれのトヌクンはそれ自䜓で、文法の互換性を簡単にしたす。

これは文法では実行できたすが、字句解析では実行できたせん。シヌケンス「=」 有効なGo1コヌドhttps://play.golang.org/p/pMTtUWgBN9で衚瀺できたす。

䞭括匧は、私の提案で解析を明確にするものです。 =!は珟圚、ブヌル倉数の宣蚀たたは代入にのみ衚瀺でき、宣蚀ず代入は珟圚、䞭括匧の盎前に衚瀺できたせんhttps暗黙のセミコロンhttps://play.golang.org/p/lhcqBhr7Teで区切られおいない限り、//play.golang.org/p/ncJyg-GMuL。

@romainmenkeいいえ。 あなただけではありたせん。 ワンラむナヌ゚ラヌ凊理の䟡倀がわかりたせん。 1行節玄できたすが、さらに耇雑になりたす。 問題は、これらの提案の倚くで、゚ラヌ凊理郚分が隠れおしたうこずです。 ゚ラヌ凊理が重芁であるため、それらを目立たなくするのではなく、コヌドを読みやすくするずいう考え方です。 簡朔さは読みやすさず同じではありたせん。 既存の゚ラヌ凊理システムに倉曎を加える必芁がある堎合は、埓来のtry-catch-finallyの方が、ここでの倚くのアむデアの目的よりもはるかに魅力的だず思いたす。

check提案が気に入ったのは、それを拡匵しお凊理するこずもできるからです。

f, err := os.Open(myfile)
check err
defer check f.Close()

他の提案もdeferず混同できるようには芋えたせん。 checkも非垞に読みやすく、知らない堎合はGoogleにずっお簡単です。 errorタむプに限定する必芁はないず思いたす。 最埌の䜍眮の戻りパラメヌタヌであるものはすべおそれを䜿甚できたす。 だから、反埩子は、必芁がある堎合がありたすcheckに぀いおNext() bool 。

私はか぀お次のようなスキャナヌを䜜成したした

func (s *Scanner) Next() bool {
    if s.Error != nil || s.pos >= s.RecordCount {
        return false
    }
    s.pos++

    var rt uint8
    if !s.read(&rt) {
        return false
    }
...

その最埌のビットは、代わりにcheck s.read(&rt)可胜性がありたす。

@carlmjohnson

他の提案もdeferず混同できるようには芋えたせん。

deferを拡匵しお、新しい構文を䜿甚しお倖郚関数から戻るこずができるず想定しおいる堎合は、その想定を他の提案にも同様に適甚できたす。

defer f.Close() =? err { return err }

@ALTreeのcheck提案では別のステヌトメントが導入されおいるため、単に゚ラヌを返す以倖のこずを行うdeferずそれを組み合わせる方法がわかりたせん。

defer func() {
  err := f.Close()
  check err, fmt.Errorf(
, err) // But this func() doesn't return an error!
}()

察比

defer f.Close() =? err { return fmt.Errorf(
, err) }

これらの提案の倚くの正圓性は、より優れた「人間工孊」ですが、それを䜜成する以倖に、これらのいずれかがどのように優れおいるかは実際にはわかりたせん。 これらはどのようにコヌドの保守性を向䞊させたすか 構成可胜性 読みやすさ 制埡フロヌの理解のしやすさ

@jimmyfrasche

これらはどのようにコヌドの保守性を向䞊させたすか 構成可胜性 読みやすさ 制埡フロヌの理解のしやすさ

前に述べたように、これらの提案の䞻な利点は、おそらく割り圓おずerr倉数のより明確なスコヌプから来る必芁がありたす19727、20148、5634、21114、およびおそらく他のさたざたなものを参照しおください゚ラヌ凊理に関連しお人々がスコヌピングの問題に遭遇する方法。

@bcmillsはモチベヌションを提䟛しおくれおありがずう、そしお申し蚳ありたせんがあなたの以前の投皿でそれを逃したした。

ただし、その前提を考えるず、すべおの倉数で䜿甚できる「割り圓おのより明確なスコヌプ」のためのより䞀般的な機胜を提䟛する方がよいのではないでしょうか。 確かに、゚ラヌ以倖の倉数のシェアも意図せずにシャドりむングしたした。

:=の珟圚の動䜜が導入されたずきのこずを芚えおいたす。そのスレッドの倚くは、暗黙の「倉数が存圚する堎合にのみ再利甚する」の代わりに、再利甚する名前に明瀺的に泚釈を付ける方法を求めおいたした。私の経隓では、すべおの埮劙な芋にくい問題が珟れる堎所である「正確に珟圚の範囲」。

†そのスレッドを芋぀けるこずができたせん誰かがリンクを持っおいたすか

Goに぀いおは改善できるず思うこずがたくさんありたすが、 :=の動䜜は、垞に1぀の重倧な間違いずしお私を驚かせたした。 たぶん、 :=の動䜜を再怜蚎するこずは、根本的な問題を解決する方法、たたは少なくずも他のより極端な倉曎の必芁性を枛らす方法ですか

@jimmyfrasche

ただし、その前提を考えるず、すべおの倉数で䜿甚できる「割り圓おのより明確なスコヌプ」のためのより䞀般的な機胜を提䟛する方がよいのではないでしょうか。

はい。 これは、 @ jbaず私が提案した=?たたは::挔算子に぀いお私が気に入っおいるこずの1぀です。これは、非゚ラヌ明らかに限定されたサブセットにもうたく拡匵されたす。

個人的には、より明瀺的なタグ付き共甚䜓/倉数/代数的デヌタ型機胜19412も参照を䜿甚するず、長期的には幞せになるず思いたすが、それは蚀語に察するはるかに倧きな倉曎です。これは、Go 1 / Go2が混圚する環境の既存のAPIに適甚されたす。

制埡フロヌの理解のしやすさ

私ず@bcmillsの提案では、あなたの目は巊偎をスキャンしお、゚ラヌのない制埡フロヌを簡単に取り蟌むこずができたす。

@ bcmills 19412の単語の少なくずも半分は私が担圓しおいるず思うので、合蚈タむプで私を売る必芁はありたせん;

゚ラヌのあるものを返すこずになるず、4぀のケヌスがありたす

  1. ただの゚ラヌ䜕もする必芁はありたせん、ただ゚ラヌを返すだけです
  2. スタッフず゚ラヌ今ずたったく同じように凊理したす
  3. 1぀たたぱラヌ合蚈タむプを䜿甚できたすtada :)
  4. 2぀以䞊のものたたぱラヌ

あなたが4を打った堎合、それは物事がトリッキヌになるずころです。 タプルタむプ構造䜓のラベル付き補品タむプに察応するラベルなし補品タむプを導入せずに、合蚈タむプを䜿甚しお「これたたぱラヌ」をモデル化する堎合は、構造䜓にすべおをバンドルしお、問題をケヌス3に枛らす必芁がありたす。

タプルタむプを導入するず、あらゆる皮類の問題や互換性の問題、奇劙な重耇が発生したす func() (int, string, error)は暗黙的に定矩されたタプルですか、それずも耇数の戻り倀は別の抂念ですか暗黙的に定矩されたタプルの堎合、それはfunc() (n int, msg string, err error)を意味したすか

合蚈タむプにはただ倚くの利点があるず思いたすが、もちろん、スコヌプの問題を修正するために䜕もしたせん。 結果のケヌスに䜕かがあったずきに゚ラヌのケヌスを単にシャドりむングするのではなく、「結果たたぱラヌ」の合蚈党䜓をシャドりむングできるため、どちらかずいえば悪化する可胜性がありたす。

@jbaそれがどのように望たしい特性であるかわかりたせん。 制埡フロヌを2次元にするずいう抂念の䞀般的な難しさを陀けば、いわば、なぜそうでないのか、私にはよくわかりたせん。 メリットを説明しおもらえたすか

タプルタむプを導入せずに[
]合蚈タむプを䜿甚しお「これたたぱラヌ」をモデル化する堎合は、構造䜓にすべおを[バンドル]する必芁がありたす。

私はそれで倧䞈倫です私たちはその方法ではるかに読みやすい呌び出しサむトを持っおいるず思いたす誀っお転眮された䜍眮バむンディングはもうありたせん、そしお12854は珟圚構造䜓の戻りに関連するオヌバヌヘッドの倚くを軜枛したす。

倧きな問題は移行です。Go1の「倀ず゚ラヌ」モデルからGo2の朜圚的な「倀たたぱラヌ」モデルにどのように移行するのでしょうか。特に、実際に「倀」を返すio.WriterようなAPIを考えるずず゚ラヌ」

合蚈タむプにはただ倚くの利点があるず思いたすが、もちろん、スコヌプの問題を修正するために䜕もしたせん。

それはあなたがそれらをどのように開梱するかに䟝存したす、それは私たちを今日の堎所に戻すず私は思いたす。 ナニオンを奜む堎合は、 =?バヌゞョンを「非察称パタヌンマッチング」APIずしお想定できたす。

i := match strconv.Atoi(str) | err error { return err }

ここで、 matchは埓来のMLスタむルのパタヌン䞀臎操䜜ですが、非網矅的な䞀臎の堎合は倀を返したすナニオンに䞀臎しない遞択肢が耇数ある堎合はinterface{}ずしお網矅的ではない詊合の倱敗で慌おるのではなく。

ここで説明されおいる問題にプログラムで察凊するパッケヌゞをhttps://github.com/mpvl/errdでチェックむンしたした蚀語の倉曎はありたせん。 このパッケヌゞの最も重芁な偎面は、゚ラヌ凊理を短瞮するだけでなく、正しく実行しやすくするこずです。 特にdeferずの盞互䜜甚においお、埓来の慣甚的な゚ラヌ凊理が芋た目よりもトリッキヌである方法に぀いお、ドキュメントで䟋を瀺したす。

ただし、これは「バヌナヌ」パッケヌゞだず思いたす。 目的は、蚀語を拡匵するための最良の方法に぀いお、いく぀かの良い経隓ず掞察を埗るこずです。 これが問題になるのであれば、ゞェネリックず非垞によく盞互䜜甚したす。

ただいく぀かの䟋に取り組んでいたすが、このパッケヌゞは実隓する準備ができおいたす。

@bcmills a million+1for12854

お気づきのように、「return Xanderror」ず「returnXor error」があるので、叀い方法を新しい方法にオンデマンドで倉換するマクロがなければ、それを回避するこずはできたせんもちろんバグがありたすたたは、「X and error」関数に必然的に䜿甚された堎合、少なくずもランタむムはパニックになりたす。

特に゚ラヌ凊理のためだけに特別なマクロを蚀語に導入するずいうアむデアは本圓に奜きではありたせん。これは、これらの提案の倚くでの私の倧きな問題です。

砂糖や魔法は倧したこずではなく、それはプラスです。

珟圚の慣性では、より機胜的な゚ラヌ凊理パラダむムぞの倧芏暡な飛躍を凊理するには、慣性が倧きすぎ、情報が少なすぎたす。

Go 2が合蚈タむプを取埗した堎合率盎に蚀っお良い意味で、「新しいスタむル」に移行するには、どちらかずいえば、非垞にゆっくりずした段階的なプロセスである必芁がありたす。゚ラヌの凊理方法の断片化ず混乱が増えおいるため、正味のポゞティブではないず思いたす。 ただし、3぀のチャネルではなくchan union { Msg1 T; Msg2 S; Err error }ようなものにすぐに䜿甚し始めたす。

これがGo1以前であり、Goチヌムが「次の6か月間、すべおを移動し、問題が発生した堎合は維持する」ず蚀うこずができれば、それは1぀のこずですが、珟圚は基本的に行き詰たっおいたす。合蚈タむプを取埗したずしおも。

お気づきのように、「return Xanderror」ず「returnXor error」があるので、叀い方法を新しい方法にオンデマンドで倉換するマクロがなければ、それを回避するこずはできたせん。

䞊で述べたように、新しい方法では、それが䜕であれ、「Xず゚ラヌを返す」をカバヌする必芁はないず思いたす。 倧倚数のケヌスが「Xたたぱラヌを返す」であり、新しい方法がそれだけを改善する堎合、それは玠晎らしいこずであり、よりたれな「Xおよび゚ラヌを返す」ために叀いGo1互換の方法を匕き続き䜿甚できたす。

@nigeltao本圓ですが、暙準ラむブラリ党䜓を既存のスタむルで維持するこずを提案しない限り、移行䞭にそれらを区別するための䜕らかの方法が必芁です。

@jimmyfrasche私はそれに぀いおの議論を構築するこずはできないず思いたす。 私の話を芋るか、リポゞトリのREADMEで䟋を芋るこずができ

@jbaは講挔を芋お、READMEを読みたした。 私はあなたが括匧/脚泚/文末脚泚/サむドノヌトのこずでどこから来おいるのか理解したしたそしお私はサむドノヌトおよび括匧のファンです。

より良い甚語がないために、偎に䞍幞な道を眮くこずが目暙である堎合、$ EDITORプラグむンは蚀語を倉曎せずに機胜し、コヌドの䜜成者の奜みに関係なく、既存のすべおのコヌドで機胜したす。

蚀語の倉曎により、構文がいくらかコンパクトになりたす。 @bcmillsは、これによりスコヌプが改善されるず述べおいたすが、 :=ずは異なるスコヌプ芏則がない限り、どのようにできるかはわかりたせんが、混乱が生じるようです。

@bcmillsあなたのコメントがわかりたせん。 あなたは明らかにそれらを区別するこずができたす。 叀い方法は次のようになりたす。

err := foo()
if err != nil {
  return n, err  // n can be non-zero
}

新しい方法は次のようになりたす

check foo()

たた

foo() || &FooError{err}

たたはバむクシェッドの色が䜕であれ。 暙準ラむブラリのほずんどは移行できるず思いたすが、すべおが移行できるわけではありたせん。

@ianlancetaylorの芁件に远加するには、゚ラヌメッセヌゞを単玔化するこずで、物事を短くするだけでなく、゚ラヌ凊理を簡単に行うこずができたす。 パニックずダりンストリヌム゚ラヌを関数を延期するたで枡すのは、正しく行うのが難しいです。

たずえば、゚ラヌが発生した堎合にファむルの曞き蟌みを䞭止するGoogle CloudStorageファむルぞの曞き蟌みに぀いお考えおみたす。

func writeToGS(ctx context.Context, bucket, dst string, r io.Reader) (err error) {
    client, err := storage.NewClient(ctx)
    if err != nil {
        return err
    }
    defer client.Close()

    w := client.Bucket(bucket).Object(dst).NewWriter(ctx)
    defer func() {
        if r := recover(); r != nil {
            w.CloseWithError(fmt.Errorf("panic: %v", r))
            panic(r)
        }
        if err != nil {
            _ = w.CloseWithError(err)
        } else {
            err = w.Close()
        }
    }
    _, err = io.Copy(w, r)
    return err
}

このコヌドの埮劙な点は次のずおりです。

  • Copyからの゚ラヌは、名前付きのreturn匕数を介しおdefer関数にこっそり枡されたす。
  • 完党に安党にするために、rからのパニックをキャッチし、パニックを再開する前に曞き蟌みを䞭止するようにしたす。
  • 最初のCloseの゚ラヌを無芖するこずは意図的なものですが、ちょっず怠惰なプログラマヌのアヌティファクトのように芋えたす。

パッケヌゞerrdを䜿甚するず、このコヌドは次のようになりたす。

func writeToGS(ctx context.Context, bucket, dst, src string, r io.Reader) error {
    return errd.Run(func(e *errd.E) {
        client, err := storage.NewClient(ctx)
        e.Must(err)
        e.Defer(client.Close, errd.Discard)

        w := client.Bucket(bucket).Object(dst).NewWriter(ctx)
        e.Defer(w.CloseWithError)

        _, err = io.Copy(w, r)
        e.Must(err)
    })
}

errd.Discardぱラヌハンドラヌです。 ゚ラヌハンドラヌを䜿甚しお、゚ラヌをラップ、ログに蚘録するこずもできたす。

e.Mustはfoo() || wrapError盞圓したす

e.Deferは䜙分であり、遅延ぞの゚ラヌの受け枡しを凊理したす。

ゞェネリックスを䜿甚するず、このコヌドは次のようになりたす。

func writeToGS(ctx context.Context, bucket, dst, src string, r io.Reader) error {
    return errd.Run(func(e *errd.E) {
        client := e.Must(storage.NewClient(ctx))
        e.Defer(client.Close, errd.Discard)

        w := client.Bucket(bucket).Object(dst).NewWriter(ctx)
        e.Defer(w.CloseWithError)

        _ = e.Must(io.Copy(w, r))
    })
}

Deferに䜿甚するメ゜ッドを暙準化するず、次のようになりたす。

func writeToGS(ctx context.Context, bucket, dst, src string, r io.Reader) error {
    return errd.Run(func(e *errd.E) {
        client := e.DeferClose(e.Must(storage.NewClient(ctx)), errd.Discard)
       e.Must(io.Copy(e.DeferClose(client.Bucket(bucket).Object(dst).NewWriter(ctx)), r)
    })
}

DeferCloseは、CloseたたはCloseWithErrorのいずれかを遞択したす。 これが良いず蚀っおいるのではなく、可胜性を瀺しおいるだけです。

ずにかく、私は先週アムステルダムのミヌトアップでこのトピックに぀いおプレれンテヌションを行いたしたが、゚ラヌ凊理を正しく行うのを簡単にする機胜は、短くするよりも䟿利であるず考えられおいるようです。

゚ラヌを改善する゜リュヌションは、物事を短くするこずよりも、物事を正しくするこずを容易にするこずに少なくずも同じくらい焊点を合わせる必芁がありたす。

@ALTree errdは、箱から出しお「掗緎された゚ラヌ回埩」を凊理したす。

@jimmyfrasche errdは、遊び堎の䟋ずほが同じように機胜したすが、゚ラヌやパニックを延期者に枡すこずもできたす。

@jimmyfrasche ほずんどの提案は、コヌドですでに達成できるこずにはあたり远加されないこずに同意したす。

@romainmenke 簡朔さに焊点が圓おられすぎおいるこずに同意したす。 物事を正しく行うこずを容​​易にするために、より倧きな焊点を圓おるべきです。

@jba errdアプロヌチを䜿甚するず、巊偎を芋るだけで゚ラヌフロヌず非゚ラヌフロヌをかなり簡単にスキャンできたすe。で始たるものはすべお゚ラヌたたは延期凊理です。 たた、どの戻り倀が゚ラヌたたは延期のために凊理され、どれが凊理されないかをスキャンするこずも非垞に簡単になりたす。

@bcmills errd自䜓はスコヌプの問題を修正したせんが、以前に宣蚀された゚ラヌ倉数などにダりンストリヌム゚ラヌを枡す必芁がないため、゚ラヌ凊理、AFAICTの問題が倧幅に軜枛されたす。

errdは完党にパニックず回埩に䟝存しおいるようです。 パフォヌマンスが倧幅に䜎䞋するようです。 このため、党䜓的な解決策かどうかはわかりたせん。

@urandom 
元のコヌドの堎合

  • 延期を䜿甚したせん。errdを䜿甚した堎合のペナルティは倧きく、玄100ns *です。
  • 慣甚的な延期を䜿甚したす。実行時間たたぱラヌは同じオヌダヌですが、倚少遅くなりたす。
  • 延期には適切な゚ラヌ凊理を䜿甚したす。実行時間はほが同じです。 延期の数が1より倧きい堎合、errdはより速くなる可胜性がありたす

その他のオヌバヌヘッド

  • 珟圚、クロヌゞャヌw.CloseをDeferに枡すず、DeferCloseたたはDeferFunc APIを䜿甚する堎合ず比范しお玄25ns *のオヌバヌヘッドが远加されたすリリヌスv0.1.0を参照。 @rscず話し合った埌、APIをシンプルに保ち、埌で最適化するこずを心配するために、それを削陀したした。
  • むンラむン゚ラヌ文字列をハンドラヌ e.Must(err, msg("oh noes!") ずしおラップするには、Go1.8で玄30nsかかりたす。 ヒント1.9では、割り圓おはただありたすが、コストを2nsで蚈枬したした。 もちろん、事前に宣蚀された゚ラヌメッセヌゞの堎合、コストはただ無芖できたす。

*2016 MacBookProで実行されおいるすべおの番号。

党䜓ずしお、元のコヌドがdeferを䜿甚しおいる堎合、コストは蚱容できるようです。 そうでない堎合、オヌスティンは延期のコストを倧幅に削枛するこずに取り組んでいるため、時間の経過ずずもにコストが䞋がる可胜性さえありたす。

ずにかく、このパッケヌゞのポむントは、我々はポむントで行く2.ケヌスで最高の蚀語の远加を構築するこずができるように感じ、今は有甚であろう代替の゚ラヌ凊理を䜿甚しおどのように経隓を埗るこずであるである珟圚の議論は、それがAの削枛にあたり焊点を圓おお単玔なケヌスでは数行ですが、埗られるものははるかに倚く、間違いなく他のポむントがより重芁です。

@jimmyfrasche 

その堎合、$ EDITORプラグむンは蚀語を倉曎せずに機胜したす

はい、それは私が話の䞭で䞻匵しおいるこずです。 ここで私は、蚀語を倉曎する堎合、それは「サむドノヌト」の抂念ず䞀臎しおいる必芁があるず䞻匵しおいたす。

@nigeltao

あなたは明らかにそれらを区別するこずができたす。 叀い方法は次のようになりたす。

私は、䜿甚のポむントではなく、宣蚀のポむントに぀いお話しおいる。

ここで説明する提案の䞭には、コヌルサむトで2぀を区別しないものもありたすが、区別するものもありたす。 「倀たたぱラヌ」を想定するオプションの1぀ || 、 try 
 catch 、 matchを遞択した堎合、䜿甚するコンパむル時゚ラヌになりたす。 「倀ず゚ラヌ」関数を䜿甚した構文であり、関数の実装者がそれを定矩する必芁がありたす。

宣蚀の時点では、珟圚、「倀ず゚ラヌ」ず「倀たたぱラヌ」を区別する方法はありたせん。

func Atoi(string) (int, error)

ず

func WriteString(Writer, String) (int, error)

戻り倀のタむプは同じですが、゚ラヌのセマンティクスが異なりたす。

@mpvl私は

WithDefaultの結果を操䜜するためのトップレベルの関数などの䞀般的なヘルパヌを無芖し、単玔化のために垞にコンテキストを䜿甚し、パフォヌマンスに関する決定を無芖するず、最小限のベアボヌンAPIは以䞋の操䜜

type Handler = func(ctx context.Context, panicing bool, err error) error
Run(context.Context, func(*E), defaults ...Handler) //egregious style but most minimal
type struct E {...}
func (*E) Must(err error, handlers ...Handler)
func (*E) Defer(func() error, handlers ...Handler)

コヌドを芋るず、䞊蚘のように定矩されおいないいく぀かの正圓な理由がわかりたすが、抂念をよりよく理解するために、コアセマンティクスを取埗しようずしおいたす。 たずえば、 IsSentinelがコアにあるかどうかはわかりたせん。

@jimmyfrasche

@bcmillsは、これによりスコヌプが改善されるず述べおいたすが、どうすればよいかわかりたせん。

䞻な改善点は、 err倉数をスコヌプ倖に保぀こずです。 これにより、 https//github.com/golang/go/issues/19727からリンクされおいるようなバグを回避でき

    res, err := ctxhttp.Get(ctx, c.HTTPClient, dirURL)
    if err != nil {
        return Directory{}, err
    }
    defer res.Body.Close()
    c.addNonce(res.Header)
    if res.StatusCode != http.StatusOK {
        return Directory{}, responseError(res)
    }

    var v struct {
        

    }
    if json.NewDecoder(res.Body).Decode(&v); err != nil {
        return Directory{}, err
    }

バグは最埌のifステヌトメントで発生したす。 Decodeからの゚ラヌは削陀されたすが、以前のチェックからのerrがただスコヌプ内にあったため、明らかではありたせん。 察照的に、 ::たたは=?挔算子を䜿甚するず、次のように蚘述されたす。

    res := ctxhttp.Get(ctx, c.HTTPClient, dirURL) =? err { return Directory{}, err }
    defer res.Body.Close()
    c.addNonce(res.Header)
    (res.StatusCode == http.StatusOK) =! { return Directory{}, responseError(res) }

    var v struct {
        

    }
    json.NewDecoder(res.Body).Decode(&v) =? err { return Directory{}, err }

ここで、圹立぀2぀のスコヌプの改善がありたす。

  1. 最初のerr 以前のGet呌び出しからはreturnブロックのスコヌプ内にあるため、埌続のチェックで誀っお䜿甚するこずはできたせん。
  2. Decode errからのDecodeは、nilnessがチェックされるのず同じステヌトメントで宣蚀されるため、宣蚀ずチェックの間にスキュヌはありたせん。

1コンパむル時に゚ラヌを明らかにするには、1だけで十分でしたが、2明らかな方法でguardステヌトメントを䜿甚する堎合は簡単に回避できたす。

@bcmills説明しおくれおありがずう

したがっお、 res := ctxhttp.Get(ctx, c.HTTPClient, dirURL) =? err { return Directory{}, err }では、 =?マクロは次のように展開されたす。

var res *http.Reponse
{
  var err error
  res, err = ctxhttp.Get(ctx, c.HTTPClient, dirURL)
  if err != nil {
    return Directory{}, err 
  }
}

それが正しければ、 :=ずは異なるセマンティクスが必芁だず蚀ったずきの意味です。

次のような独自の混乱を匕き起こすようです。

func f() error {
  var err error
  g() =? err {
    if err != io.EOF {
      return err
    }
  }
  //one could expect that err could be io.EOF here but it will never be so
}

私が䜕かを誀解しおいない限り。

うん、それは正しい拡匵です。 あなたはそれが:=ずは異なるずいうこずは正しいです、そしおそれは意図的です。

それはそれ自身の混乱を匕き起こすようです

それは本圓だ。 それが実際に混乱するかどうかは私にはわかりたせん。 そうである堎合、宣蚀甚のガヌドステヌトメントの「」バリアントを提䟛できたす「=」バリアントのみを割り圓おたす。

そしお今、挔算子は=?ず=!代わりに=? ?ず!ず綎られるべきだず私は思いたす。

res := ctxhttp.Get(ctx, c.HTTPClient, dirURL) ?: err { return Directory{}, err }

しかし

func f() error {
  var err error
  g() ?= err { (err == io.EOF) ! { return err } }
  // err may be io.EOF here.
}

@mpvl errdに関する私の䞻な関心事は、ハンドラヌむンタヌフェむスに関するものです。これは、コヌルバックの関数型パむプラむンを促進するようですが、コヌルバック/継続スタむルコヌドGoやC ++などの呜什型蚀語ず関数型の䞡方での経隓です。 MLやHaskellのような蚀語は、同等のシヌケンシャル/呜什型スタむルよりも埓うのがはるかに難しい堎合が倚いずいうこずです。これは、他のGoむディオムずも䞀臎したす。

APIの䞀郚ずしおHandlerスタむルのチェヌンを想定しおいたすか、それずもHandlerを怜蚎しおいる他の構文 Block動䜜するものなどの代甚ですか s

@bcmills私はただ、蚀語に数十の抂念を1行に導入し、1぀のものだけで機胜する魔法の機胜を䜿甚しおいたせんが、最終的に、それらがx, err := f(); if err != nil { return err }を曞くためのほんの少し短い方法以䞊のものである理由を理解したした。

@bcmills @mpvlのやる気を起こさせる䟋を曞き盎し=?提案を䜿甚しお、厄介な゚ラヌ凊理を行いたす。

func writeToGS(ctx context.Context, bucket, dst string, r io.Reader) (err error) {
        client := storage.NewClient(ctx) =? err { return err }
        defer client.Close()

        w := client.Bucket(bucket).Object(dst).NewWriter(ctx)

        defer func() {
                if r := recover(); r != nil { // r is interface{} not error so we can't use it here
                        _ = w.CloseWithError(fmt.Errorf("panic: %v", r))
                        panic(r)
                }

                if err != nil { // could use =! here but I don't see how that simplifies anything
                        _ = w.CloseWithError(err)
                } else {
                        err = w.Close()
                }
        }()

        io.Copy(w, r) =? err { return err } // what about n? does this need to be prefixed by a '_ ='?
        return nil
}

゚ラヌ凊理の倧郚分は倉曎されおいたせん。 =?は2か所でしか䜿甚できたせんでした。 そもそも、それは私が芋るこずができるような利益を実際には提䟛したせんでした。 2番目の䟋では、コヌドが長くなり、 io.Copyが2぀のものを返すずいう事実がわかりにくくなっおいるため、そこで䜿甚しない方がよいでしょう。

@jimmyfrascheそのコヌドは䟋倖であり、芏則ではありたせん。 曞きやすくするための機胜を蚭蚈するべきではありたせん。

たた、 recoverもそこにあるべきかどうか疑問に思いたす。 w.Writeたたはr.Read たたはio.Copy がパニックになっおいる堎合は、終了するのがおそらく最善です。

recoverがなければ、 deferは実際には必芁なく、関数の䞋郚は次のようになりたす。

_ = io.Copy(w, r) =? err { _ = w.CloseWithError(err); return err }
return w.Close()

@jimmyfrasche

// r is interface{} not error so we can't use it here

私の特定の衚珟https://github.com/golang/go/issues/21161#issuecomment-319434101はれロ倀に関するものであり、特に゚ラヌではないこずに泚意しおください。

// what about n? does this need to be prefixed by a '_ ='?

私はそれに぀いおもっず明確にできたかもしれたせんが、そうではありたせん。

その䟋での@mpvlのrecoverの䜿甚は特に奜きではありたせん。慣甚的な制埡フロヌよりもパニックの䜿甚を促進したすが、どちらかずいえば、無関係なrecover呌び出しを排陀する必芁があるず思いたす Go 2の暙準ラむブラリのfmt にあるものなど。

そのアプロヌチでは、そのコヌドを次のように蚘述したす。

func writeToGS(ctx context.Context, bucket, dst string, r io.Reader) (err error) {
        client := storage.NewClient(ctx) =? err { return err }
        defer client.Close()

        w := client.Bucket(bucket).Object(dst).NewWriter(ctx)
        io.Copy(w, r) =? err {
                w.CloseWithError(err)
                return err
        }
        return w.Close()
}

䞀方、慣甚的な回埩では、慣甚的な゚ラヌ凊理をサポヌトするこずを目的ずした機胜を適甚する機䌚がほずんどないずいうのは正しいこずです。 ただし、リカバリをClose操䜜から分離するず、IMOのコヌドがいくらかクリヌンになりたす。

func writeToGS(ctx context.Context, bucket, dst string, r io.Reader) (err error) {
        client := storage.NewClient(ctx) =? err { return err }
        defer client.Close()

        w := client.Bucket(bucket).Object(dst).NewWriter(ctx)
        defer func() {
                if err != nil {
                        _ = w.CloseWithError(err)
                } else {
                        err = w.Close()
                }
        }()
        defer func() {
                recover() =? r {
                        err = fmt.Errorf("panic: %v", r)
                        panic(r)
                }
        }()

        io.Copy(w, r) =? err { return err }
        return nil
}

@jba遅延ハンドラヌが再パニックになりたす。他のコンピュヌタヌのプロセスに通知しようずするため、誀っお䞍正なトランザクションをコミットするこずはありたせん朜圚的な゚ラヌ状態でも可胜であるず想定しおいたす。 それがかなり䞀般的でない堎合は、おそらくそうあるべきです。 読み取り/曞き蟌み/コピヌがパニックにならないこずに同意したすが、䜕らかの理由で合理的にパニックになる可胜性のある他のコヌドがそこにあった堎合は、最初の堎所に戻りたす。

@bcmillsの最埌のリビゞョンは芋栄えが良くなりたす実際に=?を取り出したずしおも

@jba 

_ = io.Copy(w, r) =? err { _ = w.CloseWithError(err); return err }
return w.Close()

それはただ読者のパニックの堎合をカバヌしおいたせん。 確かにこれはたれなケヌスですが、非垞に重芁なケヌスです。パニックが発生した堎合にここでCloseを呌び出すのは非垞に悪いこずです。

そのコヌドは䟋倖であり、芏則ではありたせん。 曞きやすくするための機胜を蚭蚈するべきではありたせん。

@jba この堎合、私は心から同意しerrd 、保守的な゚ラヌ凊理を簡単に行える䞀方で、ルヌルを緩和するための努力が必芁であり、他の方向に少しでも移動するものではないアプロヌチが必芁です。

@jimmyfrasche あなたの単玔化に関しおあなたは倧䜓正しいです。

  • IsSentinelは必須ではなく、䟿利で䞀般的です。 少なくずも今のずころは萜ずしたした。
  • 状態の゚ラヌぱラヌずは異なるため、APIはこれを削陀したす。 ただし、理解するために重芁ではありたせん。
  • ハンドラヌは関数である可胜性がありたすが、䞻にパフォヌマンス䞊の理由からむンタヌフェヌスです。 最適化されおいないず、倚くの人がパッケヌゞを䜿甚しないこずを私は知っおいたす。 この号のerrdに関する最初のコメントのいく぀かを参照しおください
  • コンテキストは残念です。 AppEngineはそれを必芁ずしおいたすが、他にそれほど倚くはないず思いたす。 人々がボヌクするたで、私はそれに察するサポヌトを削陀しおも倧䞈倫でしょう。

@mpvl私はそれをいく぀かのこずに絞り蟌もうずしおいたので、それがどのように機胜するか、どのように䜿甚するか、そしお私が曞いたコヌドにどのように適合するかを想像するのが簡単でした。

@jimmyfrasche 理解したしたが、APIでそれを行う必芁がない堎合は問題ありたせん。 :)

@bcmills ハンドラヌは、重芁床の高い順に、いく぀かの目的を果たしたす。

  • ゚ラヌをラップする
  • ゚ラヌを無芖するように定矩したす明瀺的にするため。䟋を参照
  • ログ゚ラヌ
  • ゚ラヌメトリック

ここでも重芁床の高い順に、これらのスコヌプを以䞋で指定する必芁がありたす。

  • ブロック
  • ラむン
  • パッケヌゞ

デフォルトの゚ラヌは、゚ラヌがどこかで凊理されるこずを保蚌しやすくするためのものです。
しかし、私はブロックレベルでしか生きられたせんでした。 私はもずもずハンドラヌの代わりにオプションを備えたAPIを持っおいたした。 ただし、その結果、APIが遅くなり、さらに䞍噚甚になりたした。

ここでは、コヌルバックの問題がそれほどひどいずは思われたせん。 ナヌザヌは、゚ラヌが発生した堎合に呌び出されるハンドラヌをランナヌに枡すこずでランナヌを定矩したす。 特定のランナヌは、゚ラヌが凊理されるブロックで明瀺的に指定されたす。 倚くの堎合、ハンドラヌは、むンラむンで枡されるラップされた文字列リテラルになりたす。 䜕が有甚で䜕がそうでないかを確認するために、少し遊んでみたす。

ずころで、ハンドラヌでのログ゚ラヌを掚奚しない堎合は、コンテキストサポヌトが削陀される可胜性がありたす。

@jba 

たた、私は回埩がそこにあるべきかどうか疑問に思いたす。 w.Writeたたはr.Readたたはio.Copyがパニックになっおいる堎合は、おそらく終了するのが最善です。

writeToGSは、パニックが発生した堎合でも終了したす!!!。これは、nil以倖の゚ラヌでCloseWithErrorを呌び出すこずを保蚌するだけです。 パニックが凊理されない堎合でも、延期は呌び出されたすが、err == nilであるため、CloudStorageでファむルが砎損する可胜性がありたす。 ここで行う正しいこずは、䞀時的な゚ラヌでCloseWithErrorを呌び出しおから、パニックを続けるこずです。

Goコヌドでこのような䟋をたくさん芋぀けたした。 io.Pipesを凊理するず、コヌドが少し埮劙になりすぎるこずもよくありたす。 ゚ラヌの凊理は、倚くの堎合、自分で芋たほど簡単ではありたせん。

@bcmills

その䟋での@mpvlのrecoverの䜿甚は特に奜きではありたせん。これは、慣甚的な制埡フロヌよりもパニックの䜿甚を促進したす。

パニックの䜿甚を少しでも奚励しようずはしおいたせん。 パニックはCloseWithErrorの盎埌に再発生するため、制埡フロヌは倉曎されないこずに泚意しおください。 パニックはパニックのたたです。
ただし、ここでrecoverを䜿甚しないのは誀りです。パニックが発生するず、延期がnil゚ラヌで呌び出され、これたでに曞き蟌たれた内容をコミットできるこずを通知したす。

ここでrecoverを䜿甚しない唯䞀のある皋床有効な議論は、任意のReaderであっおも、パニックが発生する可胜性は非垞に䜎いずいうこずですこの䟋では、理由によりReaderのタむプは䞍明です:)。
ただし、本番コヌドの堎合、これは受け入れられないスタンスです。 特に、十分な芏暡でプログラミングする堎合、これはい぀か発生するはずですパニックは、コヌドのバグ以倖の原因で発生する可胜性がありたす。

ずころで、 errdパッケヌゞを䜿甚するず、ナヌザヌがこれに぀いお考える必芁がなくなるこずに泚意しおください。 ただし、パニックが発生した堎合に゚ラヌを通知するその他のメカニズムは問題ありたせん。 パニックで延期を呌び出さないこずも機胜したすが、それ自䜓に問題がありたす。

宣蚀の時点では、珟圚、「倀ず゚ラヌ」ず「倀たたぱラヌ」を区別する方法はありたせん。

@bcmillsああ、なるほど。 別の自転車小屋の猶を開けるには、あなたが蚀うこずができるず思いたす

func Atoi(string) ?int

それ以倖の

func Atoi(string) (int, error)

ただし、WriteStringは倉曎されたせん。

func WriteString(Writer, String) (int, error)

@bcmills / @ jbaによる=? / =! / :=? / :=!提案は、同様の提案よりも気に入っおいたす。 それはいく぀かの玠晎らしい特性を持っおいたす

  • 構成可胜 =?ブロック内で=?䜿甚できたす
  • 䞀般゚ラヌタむプに固有ではなく、れロ倀のみを考慮したす
  • 改善されたスコヌプ
  • 延期で動䜜する可胜性がありたす䞊蚘の1぀のバリ゚ヌションで

それはたた、私があたり良くないず思ういく぀かの特性を持っおいたす。

構成の巣。 繰り返し䜿甚するず、さらに右にむンデントされ続けたす。 それ自䜓は必ずしも悪いこずではありたせんが、゚ラヌの原因ずなる゚ラヌを凊理する必芁がある非垞に耇雑な゚ラヌ凊理の状況では、コヌドが凊理する゚ラヌが珟圚の珟状よりもはるかに明確でなくなるず思いたす。 このような状況では、最も倖偎の゚ラヌに=?を䜿甚し、内偎の゚ラヌにif err != nilを䜿甚できたすが、これにより、゚ラヌ凊理が䞀般的に、たたは䞀般的なケヌスで本圓に改善されたしたか たぶん、䞀般的なケヌスを改善するこずが必芁なすべおですが、個人的にはそれが魅力的だずは思いたせん。

それはその䞀般性を埗るために蚀語に停りを導入したす。 「れロ倀ではない」ず定矩されおいる停りは完党に合理的ですが、私の意芋では、 if err != nil {は明瀺的であるため、 if err {よりも優れおいたす。 =? / etcを䜿おうずする実際のゆがみが芋られるず思いたす。 より自然な制埡フロヌを超えお、その停りにアクセスしようずしたす。 それは確かに䞀矩的で眉をひそめるでしょうが、それは起こりたす。 機胜の朜圚的な悪甚は、それ自䜓が機胜に察する反論ではありたせんが、考慮すべき点がありたす。

改善されたスコヌプパラメヌタヌを宣蚀するバリアントの堎合が優れおいる堎合もありたすが、スコヌプを修正する必芁がある堎合は、䞀般的にスコヌプを修正しおください。

「右端の結果のみ」のセマンティクスは理にかなっおいたすが、私には少し奇劙に思えたす。 それは議論ずいうよりは感情です。

この提案は蚀語に簡朔さを远加したすが、远加の力はありたせん。 マクロ拡匵を行うプリプロセッサずしお完党に実装できたす。 もちろん、これは望たしくありたせん。ビルドずフラグメント開発が耇雑になり、そのようなプリプロセッサは、型を認識しお衛生的である必芁があるため、非垞に耇雑になりたす。 私は「プリプロセッサを䜜るだけ」ず蚀っお华䞋しようずはしおいたせん。 私はこれを、この提案が完党に砂糖であるこずを指摘するためだけに提起したす。 Goでは今できなかったこずは䜕もできたせん。 よりコンパクトに曞くこずができたす。 私は独断的に砂糖に反察しおいたせん。 慎重に遞択された蚀語の抜象化には力がありたすが、それが砂糖であるずいう事実は、いわば無実であるこずが蚌明されるたで、それが👎ず芋なされるべきであるこずを意味したす。

挔算子のlhsはステヌトメントですが、ステヌトメントの非垞に限られたサブセットです。 そのサブセットに含める芁玠はかなり自明ですが、他に䜕もないずしおも、倉曎に察応するために蚀語仕様の文法をリファクタリングする必芁がありたす。

のようなものになりたす

func F() (S, T, error)

func MustF() (S, T) {
  return F() =? err { panic(err) }
}

蚱可されおいる

もしも

defer f.Close() :=? err {
    return err
}

どういうわけか同等でなければならないこずが蚱可されたす

func theOuterFunc() (err error) {
  //...
  defer func() {
    if err2 := f.Close(); err2 != nil {
      err = err2
    }
  }()
  //...
}

これは非垞に問題があり、非垞に混乱する状況を匕き起こす可胜性があり、非垞に非Goのような方法で、暗黙的にクロヌゞャを割り圓おるこずのパフォヌマンスぞの圱響を隠しおいるこずを無芖したす。 別の方法は、暗黙のクロヌゞャからreturn返し、 func()からタむプerror倀を返すこずができないずいう゚ラヌメッセヌゞを衚瀺するこずです。鈍い。

ただし、実際には、スコヌプの修正がわずかに改善されおいるこずを陀けば、Goでの゚ラヌの凊理で盎面する問題は修正されたせん。 せいぜいif err != nil { return err }ず入力するのは厄介で、21182で衚珟したわずかな読みやすさの懞念を法ずしおです。 2぀の最倧の問題は

  1. ゚ラヌを凊理する方法を考えおいたす—そしおそれに぀いお蚀語ができるこずは䜕もありたせん
  2. ゚ラヌを内省しお、状況によっおは䜕をすべきかを刀断したす。 errorsパッケヌゞからのサポヌトによる远加の芏則は、すべおの問題を解決できるわけではありたせんが、ここでは倧いに圹立ちたす。

それだけが問題ではなく、倚くの人がすぐに他の偎面を芋぀けたすが、私が最も時間を費やし、䜕よりも厄介で厄介な問題だず思いたす。

もちろん、私が䜕かを台無しにしたこずを怜出するためのより良い静的分析は垞にありがたいですそしお䞀般的に、このシナリオだけではありたせん。 ゜ヌスの分析を容易にする蚀語の倉曎ず芏則により、これらがより有甚になるこずも興味深いでしょう。

私はこれに぀いおたくさん曞いたばかりですたくさんごめんなさいが、私は提案を华䞋しおいたせん。 メリットはあるず思いたすが、バヌをクリアしたり、重さを匕いたりするこずには確信が持おたせん。

@jimmyfrasche

=の珟圚の動䜜が導入されたずきのこずを芚えおいたす。そのスレッドの倚くは、暗黙の「珟圚のスコヌプに倉数が存圚する堎合にのみ再利甚する」ではなく、再利甚する名前に明瀺的に泚釈を付ける方法を求めおいたした。 「私の経隓では、これはすべおの埮劙な芋にくい問題が珟れる堎所です。

†そのスレッドを芋぀けるこずができたせん誰かがリンクを持っおいたすか

Goがリリヌスされたずきに関わっおいない限り、別のスレッドを芚えおいるに違いないず思いたす。 リリヌス盎前の2009/11/9の仕様には、次のようなものがありたす。

通垞の倉数宣蚀ずは異なり、短い倉数宣蚀は、元々同じタむプの同じブロックで宣蚀されおいお、空癜以倖の倉数の少なくずも1぀が新しい堎合に、倉数を再宣蚀できたす。

以前は=のある蚀語を䜿甚しおいたしたが、その再利甚ルヌルがなく、同じものの新しい名前を考えるのは面倒だったので、初めお仕様を読んでそれが玠晎らしいルヌルだず思ったずきのこずを芚えおいたす。

@mpvl
あなたの元の䟋のトリッキヌさは、より倚くの結果だず思いたす
Goの゚ラヌ凊理自䜓よりもそこで䜿甚しおいるAPI。

これは興味深い䟋ですが、特に
パニックが発生した堎合、通垞はファむルを閉じたくないので、
通垞の「deferw.Close」むディオムは機胜したせん。

あるずきに閉じるを呌び出すこずを避ける必芁がなかった堎合
パニック、そしおあなたはするこずができたす

func writeToGS(ctx context.Context, bucket, dst string, r io.Reader) (err error) {
    client, err := storage.NewClient(ctx)
    if err != nil {
        return err
    }
    defer client.Close()

    w := client.Bucket(bucket).Object(dst).NewWriter(ctx)
    defer w.Close()
    _, err = io.Copy(w, r)
    if err != nil {
        w.CloseWithError(err)
    }
    return err
}

Closeを呌び出すようにセマンティクスが倉曎されたず仮定したす
CloseWithErrorを呌び出した埌は、䜕もしたせん。

もうそんなに悪くはないず思いたす。

パニックが発生したずきにファむルが゚ラヌなしで曞き蟌たれないずいう芁件があっおも、察応するのはそれほど難しいこずではありたせん。 たずえば、Closeの前に明瀺的に呌び出す必芁があるFinalize関数を远加したす。

    w := client.Bucket(bucket).Object(dst).NewWriter(ctx)
    defer w.Close()
    _, err = io.Copy(w, r)
    return w.Finalize(err)

パニック゚ラヌメッセヌゞを添付するこずはできたせんが、適切なログを蚘録するこずで、それをより明確にするこずができたす。
Closeメ゜ッドには、recover呌び出しが含たれおいる可胜性もありたすが、それが
実際には本圓に悪い考えです...

ただし、この䟋のパニック回埩の偎面は、99以䞊の゚ラヌ凊理のケヌスではパニック回埩が行われないため、このコンテキストではやや赀ニシンだず思いたす。

@rogpeppe 

パニック゚ラヌメッセヌゞを添付するこずはできたせんが、適切なログを蚘録するこずで、それをより明確にするこずができたす。

それは問題ではないず思いたす。

提案されたAPIの倉曎は軜枛されたすが、問題はただ完党には解決されおいたせん。 必芁なセマンティクスでは、他のコヌドも適切に動䜜する必芁がありたす。 以䞋の䟋を考えおみたしょう。

r, w := io.Pipe()
go func() {
    var err error                // used to intercept downstream errors
    defer func() {
        w.CloseWithError(err)
    }()

    r, err := newReader()
    if err != nil {
        return
    }
    defer func() {
        if errC := r.Close(); errC != nil && err == nil {
            err = errC
        }
    }
    _, err = io.Copy(w, r)
}()
return r

それ自䜓で、このコヌドは、゚ラヌ凊理がトリッキヌであるか、少なくずも厄介である可胜性があるこずを瀺しおいたすそしお、これが他の提案でどのように改善されるのか興味がありたすそれはステルスにダりンストリヌム゚ラヌを倉数に枡し、少しもありたす正しい゚ラヌが枡されるこずを保蚌するための䞍栌奜なifステヌトメント。 どちらも「ビゞネスロゞック」から気をそらしすぎおいたす。 ゚ラヌ凊理がコヌドを支配したす。 そしお、この䟋はただパニックを凊理しおいたせん。

完党を期すために、 errdこの_はパニックを正しく凊理し、次のようになりたす。

r, w := io.Pipe()
go errd.Run(func(e *errd.E) {
    e.Defer(w.CloseWithError)

    r, err := newReader()
    e.Must(err)
    e.Defer(r.Close)

    _, err = io.Copy(w, r)
    e.Must(err)
})
return r

䞊蚘のリヌダヌ errdを䜿甚しおいないがリヌダヌずしおwriteToGSに枡され、newReaderによっお返されたio.Readerがパニックになった堎合でも、提案されたAPI修正で誀ったセマンティクスが発生したす正垞に終了する可胜性がありたすパむプがパニックで閉じられた埌のGSファむルがnil゚ラヌで衚瀺されたす。

これもポむントを蚌明したす。 Goでの適切な゚ラヌ凊理に぀いお掚論するのは簡単ではありたせん。 errdでコヌドを曞き盎すず、コヌドがどのように芋えるかを調べたずころ、バグのあるコヌドがたくさん芋぀かりたした。 errdパッケヌゞの単䜓テストを䜜成するずきに、適切な慣甚的なGo゚ラヌ凊理を䜜成するこずがいかに困難で埮劙であるかを実際に孊びたした。 :)

提案されたAPIの倉曎に代わる方法は、パニック時に延期をたったく凊理しないこずです。 これには独自の問題があり、問題を完党に解決するこずはできず、おそらく元に戻すこずはできたせんが、いく぀かの優れた品質がありたす。

いずれにせよ、簡朔さに焊点を圓おたものではなく、゚ラヌ凊理の埮劙さを軜枛する蚀語の倉曎が最善でしょう。

@mpvl
Goの゚ラヌ凊理コヌドで、別の関数を䜜成するず問題が解決するこずがよくありたす。 私はあなたのコヌドをこのようなものの䞊に曞くでしょう

func something() {
    r, w := io.Pipe()
    go func() {
        err := copyFromNewReader(w)
        w.CloseWithError(err)
    }()
    ...
}

func copyFromNewReader(w io.Writer) error {
    r, err := newReader()
    if err != nil {
        return err
    }
    defer r.Close()
    _, err = io.Copy(w, r)
    return err
}()

r.Closeは有甚な゚ラヌを返さないず想定しおいたす。リヌダヌを最埌たで読み、io.EOFのみが発生した堎合は、閉じたずきに゚ラヌが返されるかどうかはほが間違いなく問題ではありたせん。

私はerrdAPIに熱心ではありたせん-開始されるゎルヌチンに敏感すぎたす。 䟋 https 
function inはプログラムの正確さに圱響を䞎えるべきではありたせんが、errdを䜿甚する堎合は圱響したす。 パニックが抜象化の境界を安党に通過するこずを期埅しおいたすが、Goにはありたせん。

@mpvl

w.CloseWithErrorerrを延期する

ずころで、この行は垞にCloseWithErrorをnil゚ラヌ倀で呌び出したす。 私はあなたがする぀もりだったず思いたす
曞きたす

defer func() { 
   w.CloseWithError(err)
}()

@mpvl

返される゚ラヌこずに泚意しおくださいClose䞊の方法io.Readerほずんどない有甚ですがhttps://github.com/golang/go/issues/20803#issuecomment-312318808でリストを参照しおください。

これは、今日の䟋を次のように曞く必芁があるこずを瀺唆しおいたす。

r, w := io.Pipe()
go func() (err error) {
    defer func() { w.CloseWithError(err) }()

    r, err := newReader()
    if err != nil {
        return err
    }
    defer r.Close()

    _, err = io.Copy(w, r)
    return err
}()
return r

...少し冗長であるこずを陀けば、これは私には完党に問題ないようです。

パニックが発生した堎合にw.CloseWithErrorにnil゚ラヌが枡されるのは事実ですが、プログラム党䜓はずにかくその時点で終了したす。 nil゚ラヌで閉じないこずが重芁な堎合は、単玔な名前倉曎ず1行の远加行です。

-go func() (err error) {
-   defer func() { w.CloseWithError(err) }()
+go func() (rerr error) {
+   rerr = errors.New("goroutine exited by panic")
+   defer func() { w.CloseWithError(rerr) }()

@rogpeppe 確かに、ありがずう。 :)

はい、私はゎルヌチンの問題を認識しおいたす。 それは厄介ですが、おそらく獣医のチェックで捕たえるのは難しいこずではありたせん。 ずにかく、私はerrdを最終的な解決策ずしおではなく、゚ラヌ凊理に最適に察凊する方法を経隓する方法ずしお芋おいたす。 理想的には、同じ問題を解決する蚀語の倉曎がありたすが、適切な制限が課せられたす。

パニックが抜象化の境界を安党に通過するこずを期埅しおいたすが、Goにはありたせん。

それは私が期埅しおいるこずではありたせん。 この堎合、APIが成功しなかったずきに成功を報告しないこずを期埅しおいたす。 最埌のコヌドは、ラむタヌにdeferを䜿甚しないため、正しく凊理されたす。 しかし、これは非垞に埮劙です。 この堎合、慣甚的なものず芋なされるため、倚くのナヌザヌはdeferを䜿甚したす。

たぶん、獣医のチェックのセットは、延期の問題のある䜿甚法を捕らえるこずができたす。 それでも、元の「慣甚的な」コヌドず最埌にリファクタリングされたコヌドの䞡方で、他の点では非垞に単玔なコヌドである䜕かの埮劙な゚ラヌ凊理を回避するための倚くの調敎がありたす。 回避策のコヌドは、特定の゚ラヌケヌスを凊理する方法を理解するためのものではなく、生産的な䜿甚に䜿甚できる玔粋な脳のサむクルの無駄です。

具䜓的には、 errdから孊がうずしおいるのは、単玔に䜿甚した堎合に゚ラヌ凊理がより簡単になるかどうかです。 私が芋るこずができるものから、倚くの耇雑さず埮劙さが消えたす。 そのセマンティクスの偎面を新しい蚀語機胜に䜓系化できるかどうかを確認するのは良いこずです。

@jimmyfrasche

それはその䞀般性を埗るために蚀語に停りを導入したす。

それは非垞に良い点です。 停りに関する通垞の問題は、ブヌル関数を呌び出すのを忘れたり、nilぞのポむンタヌを逆参照するのを忘れたりするこずから生じたす。

挔算子をnillable型でのみ機胜するように定矩するこずで、埌者に察凊できたすそしお、ほずんど圹に立たないため、結果ずしお=!を削陀する可胜性がありたす。

関数型では機胜しないように、たたはポむンタヌ型たたはむンタヌフェヌス型でのみ機胜するようにさらに制限するこずで、前者に察凊できたす。その堎合、倉数がブヌル倀ではないこずは明らかで

[ MustF ]のようなものは蚱可されたすか

はい。

[ defer f.Close() :=? err { ]が蚱可されおいる堎合、それはどういうわけか同等でなければなりたせん
[ defer func() { 
 }() ]。

必ずしもそうではありたせん。 独自のセマンティクスを持぀こずができたす無名関数よりもcall/ccように。 defer =?を䜿甚するための仕様倉曎を提案しおいたせん少なくずも文法の倉曎が必芁ですので、そのような定矩がどれほど耇雑になるかは正確にはわかりたせん。 。

2぀の最倧の問題は[
] 2。゚ラヌを内省しお、状況によっおは䜕をすべきかを刀断するこずです。

これは実際にはもっず倧きな問題であるこずに同意したすが、この問題ずほが盎亀しおいるように芋えたすこれは、定型文ずそれに関連する゚ラヌの可胜性を枛らすこずに関するものです。

 @ rogpeppe 、 @ davecheney 、 @ dsnet 、 @ crawshaw 、私、および他のいく぀かの人は、゚ラヌを怜査するためのAPIに぀いおGopherConで玠晎らしい議論をしたこずを忘れおいたす。その前に、いく぀かの良い提案が芋られるこずを願っおいたす。 、しかし私は本圓にそれは別の問題の問題だず思いたす。

@bcmills このコヌドには2぀の問題がありたす1 @rogpeppeが述べたのず同じ

それ以倖の堎合、Closeによっお返される゚ラヌは無芖できるこずが倚いこずに同意したす。 ただし、垞にではありたせん最初の䟋を参照。

私のかなり単玔な䟋私自身の䟋を含むで4぀たたは5぀の誀った提案が行われたこずは少し驚くべきこずですが、Goでの゚ラヌ凊理は簡単ではないずただ䞻匵しなければならないようです。 :)

@bcmills 

パニックが発生した堎合にw.CloseWithErrorにnil゚ラヌが枡されるのは事実ですが、プログラム党䜓はずにかくその時点で終了したす。

したすか そのゎルヌチンの延期はただ呌び出されたす。 私が理解しおいる限り、それらは完了するたで実行されたす。 この堎合、Closeはio.EOFを通知したす。

たずえば、 https//play.golang.org/p/5CFbsAe8zFを参照しお

同様に、他のコヌドは、パニック状態のゎルヌチン䟋のようなから誀ったio.EOFを受け取り、成功を完了し、パニック状態のゎルヌチンがパニックを再開する前にファむルをGSにコミットする堎合がありたす。

次の議論は次のようになるかもしれたせんバグのあるコヌドを曞かないでください、しかし

  • 次に、これらのバグの防止を容易にし、
  • パニックは、OOMなどの倖郚芁因によっお匕き起こされる可胜性がありたす。

nil゚ラヌで閉じないこずが重芁な堎合は、単玔な名前倉曎ず1行の远加行です。

終了時にio.EOFを通知するために、nilで閉じる必芁があるため、機胜したせん。

nil゚ラヌで閉じないこずが重芁な堎合は、単玔な名前倉曎ず1行の远加行です。

終了時にio.EOFを通知するために、nilで閉じる必芁があるため、機胜したせん。

なぜだめですか 最埌のreturn errは、 rerrをnilたす。

@bcmills ああ、あなたが今䜕を意味しおいるのかわかりたす。 はい、うたくいくはずです。 ただし、行数に぀いおは心配しおいたせんが、コヌドの埮劙さに぀いおは心配しおいたす。

これは、可倉シャドりむングず同じカテゎリの問題であり、発生する可胜性はわずかに䜎くなりたすおそらく悪化したす。議論の䜙地のあるほずんどの可倉シャドりむングのバグは、優れた単䜓テストで発生したす。 任意のパニックをテストするのは困難です。

倧芏暡に運甚する堎合、このようなバグが発生するこずはほが確実です。 私は偏執的かもしれたせんが、デヌタの損倱や砎損に぀ながる可胜性がはるかに䜎いシナリオを芋おきたした。 通垞、これは問題ありたせんが、トランザクション凊理gsファむルの曞き蟌みなどには適しおいたせん。

私があなたの提案を別の構文でハむゞャックするこずを気にしないでください-人々はこのようなものに぀いおどのように感じたすか

return err if f, err := os.Open("..."); err != nil

@SirCmpwnそれは

それは公平ですが、あなたの提案は私にも䞍快感を䞎えたす-それはナヌザヌが期埅するように蚓緎された方法ずは異なる振る舞いをする䞍透明な構文||を導入したす|| 振る舞う。 正しい解決策が䜕であるかわからない、それをもう少し熟考するでしょう。

@SirCmpwnはい、元の投皿で述べたように、「この提案を曞いおいるのは、䞻にGo゚ラヌ凊理を簡玠化したい人に、゚ラヌを倉曎せずに返すだけでなく、゚ラヌの呚りにコンテキストを簡単にラップできるようにする方法を考えるように促すためです。 。」 私はできる限り提案を曞きたしたが、それが採甚されるこずは期埅しおいたせん。

了解した。

これはもう少し過激ですが、マクロ駆動型のアプロヌチの方がうたくいくかもしれたせん。

f = try!(os.Open("..."))

try!は、タプルの最埌の倀を食べお、nilでない堎合はそれを返し、それ以倖の堎合はタプルの残りの倀を返したす。

私たちの問題の説明は、

Goでの゚ラヌ凊理は、冗長で反埩的です。 Goの゚ラヌ凊理の慣甚的な圢匏は、゚ラヌ以倖の制埡フロヌを確認するこずをより困難にし、冗長性は、特に初心者にずっお魅力的ではありたせん。 珟圚たで、この問題に察しお提案された゜リュヌションは、通垞、職人による1回限りの゚ラヌ凊理機胜を必芁ずし、゚ラヌ凊理の局所性を枛らし、耇雑さを増しおいたす。 Goの目暙の1぀は、ラむタヌに゚ラヌ凊理ず回埩を怜蚎させるこずであるため、゚ラヌ凊理の改善もその目暙に基づいお構築する必芁がありたす。

この問題の説明に察凊するために、Go2.xでの゚ラヌ凊理の改善に関する次の目暙を提案したす。

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

この提案の評䟡

f.Close() =? err { return fmt.Errorf(
, err) }

それらの目暙によれば、私はそれが目暙1でうたく成功するず結論付けたす。 それが2でどのように圹立぀かはわかりたせんが、コンテキストを远加する可胜性も䜎くなりたせん私自身の提案は2でこの匱点を共有しおいたした。 ただし、3ず4では実際には成功したせん。
1他の人が蚀っおいるように、゚ラヌ倀のチェックず割り圓おは䞍透明で異垞です。 ず
2 =?構文も珍しいです。 類䌌しおいるが異なる=!構文ず組み合わせるず、特に混乱したす。 人々が圌らの意味に慣れるにはしばらく時間がかかりたす。 ず
3゚ラヌずずもに有効な倀を返すこずは十分に䞀般的であるため、新しい゜リュヌションでもそのケヌスを凊理する必芁がありたす。

゚ラヌ凊理をブロックにするのは良い考えかもしれたせんが、他の人が瀺唆しおいるように、それはgofmtぞの倉曎ず組み合わされおいたす。 私の提案ず比范しお、それは䞀般性を改善したす。これは、目暙4に圹立ち、芪しみやすさは、コンテキストを远加しお゚ラヌを返すずいう䞀般的なケヌスの簡朔さを犠牲にしお、目暙3に圹立ちたす。

芁玄で私に尋ねた堎合、䞊蚘の゚ラヌ凊理の改善目暙を満たしおいる限り、゚ラヌ凊理の特定の゜リュヌションよりも䞀般的な゜リュヌションの方が望たしいこずに同意したかもしれたせん。 しかし、この議論を読んでそれに぀いおもっず考えたので、特定の解決策を凊理する゚ラヌがより明確で単玔になるず信じる傟向がありたす。 Goの゚ラヌは単なる倀ですが、゚ラヌ凊理はプログラミングの重芁な郚分を構成するため、゚ラヌ凊理コヌドを明確か぀簡朔にするための特定の構文が適切であるず思われたす。 スコヌピングや構成可胜性などの他の目暙ず組み合わせるず、すでに難しい問題゚ラヌ凊理のクリヌンな解決策を考え出すがさらに難しく耇雑になるのではないかず思いたす。

かかわらず、しかし、圌の蚘事のうち@rscポむントは、ず行く2に向けお、どちらの問題声明、目暙や構文の提案は、問題が重芁であるこずを蚌明しおいる経隓を報告せずに、事前に可胜性がありたす。 たぶん、さたざたな構文の提案に぀いお議論する代わりに、デヌタをサポヌトするために掘り䞋げ始めるべきでしょうか

ずはいえ、 @ rscが圌の蚘事

人間工孊が重芁であるず仮定すれば、これは自明だず思いたす。 Goコヌドベヌスを開き、物事を也かしたり、蚀語が察凊できる人間工孊を改善したりする機䌚がある堎所を探したす。珟圚、゚ラヌ凊理は明らかに倖れ倀です。 Toward Go 2のアプロヌチは、回避策のある問題を無芖するこずを誀っお䞻匵しおいる可胜性があるず思いたす。この堎合、人々はただニダリず笑っお耐えたす。

if $val, err := $operation($args); err != nil {
  return err
}

コヌドよりも定型的なものが倚い堎合、問題は自明の私芋です。

@billyh

f.Close() =? err { return fmt.Errorf(
, err) }の圢匏は、過床に冗長で混乱しおいるように感じたす。 個人的には、゚ラヌ郚分がブロックになっおいるずは思いたせん。 必然的に、1行ではなく3行に分散されるこずになりたす。さらに、゚ラヌを返す前に゚ラヌを倉曎する以䞊のこずを行う必芁があるオフ倉曎では、珟圚のif err != nil { ... }䜿甚できたす。

=?挔算子も少し混乱したす。 そこで䜕が起こっおいるのかはすぐにはわかりたせん。

このようなもので
file := os.Open("/some/file") or raise(err) errors.Wrap(err, "extra context")
たたは速蚘
file := os.Open("/some/file") or raise
ず延期
defer f.Close() or raise(err2) errors.ReplaceIfNil(err, err2)
はもう少し蚀葉が倚く、単語を遞択するこずで最初の混乱を枛らすこずができたす぀たり、 raiseをPythonなどの他の蚀語の同様のキヌワヌドにすぐに関連付けるか、raiseが゚ラヌ/ last-non-を発生させるず掚枬する可胜性がありたすデフォルト-スタックを呌び出し元に蚭定したす。

これは、倪陜の䞋で起こりうるすべおのあいたいな゚ラヌ凊理を解決しようずしない、優れた必須の゜リュヌションでもありたす。 はるかに、野生での゚ラヌ凊理の最倧のチャンクは、䞊蚘の性質のものです。 埌者に぀いおは、珟圚の構文も圹立ちたす。

線集
「魔法」を少し枛らしたい堎合は、前の䟋も次のようになりたす。
file, err := os.Open("/some/file") or raise errors.Wrap(err, "extra context")
file, err := os.Open("/some/file") or raise err
defer err2 := f.Close() or errors.ReplaceIfNil(err, err2)
個人的には、前の䟋の方が、ここでのように分割するのではなく、完党な゚ラヌ凊理を右に移動するので、より良いず思いたす。 しかし、これはもっず明確かもしれたせん。

私たちの問題の説明は、...

私は問題の蚘述に同意したせん。 別の方法を提案したいず思いたす。


蚀語の芳点からは、゚ラヌ凊理は存圚したせん。 Goが提䟛するのは、事前に宣蚀された゚ラヌタむプだけです。それでも、本圓に新しいものは䜕も有効にしないため、䟿宜䞊です。 ゚ラヌは単なる倀です。 ゚ラヌ凊理は通垞のナヌザヌコヌドです。 蚀語POVからは特別なこずは䜕もありたせんし、特別なこずもありたせん。 ゚ラヌ凊理の唯䞀の問題は、この䟡倀のある矎しいシンプルさを絶察に排陀しなければならないず考える人がいるこずです。

Cznicの蚀う通りに沿っお、単なる゚ラヌ凊理以䞊のこずに圹立぀゜リュヌションがあるず䟿利です。

゚ラヌ凊理をより䞀般的にする1぀の方法は、共甚䜓型/合蚈型ずアンラップの芳点から゚ラヌ凊理を考えるこずです。 SwiftずRustはどちらも  構文は、Rustは少し䞍安定だず思いたすが。

合蚈型を高レベルの抂念にしたくない堎合は、タプルが実際にはGoの䞀郚ではないように、耇数の戻りの䞀郚にするこずができたすが、それでも耇数の戻りを行うこずができたす。

Swiftに觊発された構文の刺し傷

func Failable() (*Thingie | error) {
    ...
}

guard thingie, err := Failable() else { 
    return wrap(err, "Could not make thingie)
}
// err is not in scope here

これは、次のような他の甚途にも䜿甚できたす。

guard val := myMap[key] else { val = "default" }

@bcmillsず@jbaによっお提案された゜リュヌション=?は、゚ラヌだけでなく、れロ以倖の抂念です。 この䟋は正垞に機胜したす。

func Foo()(Bar, Recover){}
bar := Foo() =? recover { log.Println("[Info] Recovered:", recover)}

この提案の䞻なアむデアは、読みやすくするために、サむドノヌト、コヌドの䞻な目的を分離し、二次的なケヌスを脇に眮くこずです。
私にずっお、Goコヌドの読み取りは、堎合によっおは継続的ではなく、倚くの堎合、 if err!= nil {return err}でアむデアを止めおいるので、私たちが読んだ本のように、サむドノヌトのアむデアは私にずっお興味深いようです。䞻なアむデアを継続的に読んでから、サむドノヌトを読んでください。  @jbaトヌク
非垞にたれな状況では、゚ラヌが関数の䞻な目的であり、おそらく回埩䞭です。 通垞、゚ラヌが発生した堎合は、コンテキスト、ログ、リタヌンを远加したす。このような堎合、サむドノヌトを䜿甚するずコヌドが読みやすくなりたす。
それが最良の構文であるかどうかはわかりたせん。特に、2番目の郚分のブロックは奜きではありたせん。サむドノヌトは小さくする必芁があり、行は十分である必芁がありたす。

bar := Foo() =? recover: log.Println("[Info] Recovered:", recover)

@billyh

  1. 他の人が蚀っおいるように、゚ラヌ倀のチェックず割り圓おは䞍透明で珍しいものです。 ず

もっず具䜓的に蚀っおください。「䞍透明で珍しい」はひどく䞻芳的です。 提案が混乱するだろうず思うコヌドの䟋をいく぀か挙げおいただけたすか

  1. = 構文も珍しいです。 [
]

それが機胜のIMOです。 誰かが異垞なオペレヌタヌを芋た堎合、正確であるかどうかわからないこずを単に想定するのではなく、それが䜕をしおいるのかを調べる傟向があるのではないかず思いたす。

  1. ゚ラヌずずもに有効な倀を返すこずは十分に䞀般的であるため、新しい゜リュヌションでもそのケヌスを凊理する必芁がありたす。

したす

提案を泚意深く読んでください。 =?は、 Block評䟡する前に割り圓おを実行するため、その堎合にも䜿甚できたす。

n := r.Read(buf) =? err {
  if err == io.EOF {
    [
]
  }
  return err
}

たた、 @ nigeltaoが指摘したように、既存の 'n、err= r.Readbuf `パタヌンをい぀でも䜿甚できたす。 䞀般的なケヌスのスコヌプず定型文を支揎する機胜を远加しおも、それをたれなケヌスにも䜿甚する必芁があるこずを意味するわけではありたせん。

たぶん、さたざたな構文の提案に぀いお議論する代わりに、デヌタをサポヌトするために掘り䞋げ始めるべきでしょうか

Ianが元の投皿でリンクした倚数の問題およびそれらの䟋を参照しおください。
https://github.com/golang/go/wiki/ExperienceReports#error-handlingも参照しお

これらのレポヌトから具䜓的な掞察を埗た堎合は、それを共有しおください。

@urandom

個人的には、゚ラヌ郚分がブロックになっおいるずは思いたせん。 必然的に、それはそれを1行ではなく3行に広げるこずになりたす。

ブロックの目的は2぀ありたす。

  1. ゚ラヌを生成する匏ずそのハンドラヌの間に明確な芖芚的および文法的な区切りを提䟛し、
  2. より広い範囲の゚ラヌ凊理を可胜にするため元の投皿で@ianlancetaylorが述べた目暙ごずに。

3行察1は、蚀語の倉曎でさえありたせん。行数が最倧の懞念事項である堎合は、 gofmt倉曎するだけで察凊できたす。

file, err := os.Open("/some/file") or raise errors.Wrap(err, "extra context")
file, err := os.Open("/some/file") or raise err

すでにreturnずpanicたす; それらの䞊にraiseを远加するず、ゲむンが少なすぎるために関数を終了する方法が倚すぎるように芋えたす。

defer err2 := f.Close() or errors.ReplaceIfNil(err, err2)

errors.ReplaceIfNil(err, err2)には、非垞に珍しい参照枡しのセマンティクスが必芁です。
代わりに、ポむンタでerr枡すこずができたす。

defer err2 := f.Close() or errors.ReplaceIfNil(&err, err2)

しかし、それでも私には非垞に奇劙に思えたす。 orトヌクンは、匏、ステヌトメント、たたはその他のものを構成したすか より具䜓的な提案が圹立぀でしょう。

@carlmjohnson

guard 
 elseステヌトメントの具䜓的な構文ずセマンティクスは䜕でしょうか 私には、トヌクンず可倉䜍眮が入れ替わった=?たたは::よく䌌おいるように芋えたす。 繰り返しになりたすが、より具䜓的な提案が圹立ちたすあなたが念頭に眮いおいる実際の構文ずセマンティクスは䜕ですか

@bcmills
架空のReplaceIfNilは単玔です。

func ReplaceIfNil(original, replacement error) error {
   if original == nil {
       return replacement
   }
   return original
}

それに぀いおは䜕も珍しいこずはありたせん。 たぶん名前...

orは二項挔算子であり、巊偎のオペランドはIdentifierListたたはPrimaryExprのいずれかです。 前者の堎合、右端の識別子になりたす。 次に、巊偎のオペランドがデフォルト倀でない堎合に、右偎のオペランドを実行できるようにしたす。

そのため、埌で匏の倀を取埗する関数Resultの最埌のパラメヌタヌを陀いお、デフォルト倀を返す魔法を実行するために、埌で別のトヌクンが必芁になりたした。
IIRC、少し前に、面倒なデフォルト倀の初期化の代わりに、蚀語に「...」などを远加するずいう別の提案がありたした。 そのため、党䜓は次のようになりたす。

f, err := os.Open("/some/file") or return ..., errors.Wrap(err, "more context")

ブロックに関しおは、より広いハンドリングが可胜になるこずを理解しおいたす。 この提案の範囲が、仮想の80をカバヌするのではなく、考えられるすべおのシナリオに察応するこずであるかどうかは、個人的にはわかりたせん。 そしお、私は個人的に、結果が䜕行かかるかが重芁であるず信じおいたす=のようなあいたいなトヌクンを䜿甚する堎合、それが私の最倧の関心事であるずは決しお蚀いたせんでしたが、実際には読みやすさ、たたはその欠劂です。 この新しい提案が䞀般的なケヌスで耇数の行にたたがる堎合、私は個人的に次のようなものよりもその利点を理解しおいたせん。

if f, err := os.Open("/some/file"); err != nil {
     return errors.Wrap(err, "more context")
}
  • 䞊蚘で定矩された倉数がifスコヌプ倖で利甚可胜になる堎合。
    そしお、それでも、これらの゚ラヌ凊理ブロックの芖芚的なノむズのために、そのようなステヌトメントが2぀しかない関数は読みにくくなりたす。 そしお、それは、倖出先での゚ラヌ凊理に぀いお議論するずきに人々が抱く䞍満の1぀です。

@urandom

orは二項挔算子であり、巊偎のオペランドはIdentifierListたたはPrimaryExprのいずれかです。 [
]次に、巊偎のオペランドがデフォルト倀でない堎合に、右偎のオペランドを実行できるようにしたす。

Goの二項挔算子は匏であり、ステヌトメントではないため、 orを二項挔算子にするず倚くの疑問が生じたす。 より倧きな匏の䞀郚ずしおのorのセマンティクスは䜕ですかたた、 :=投皿した䟋でそのゞャむブはどのようになりたすか

それが実際にステヌトメントであるず仮定するず、右偎のオペランドは䜕ですか それが匏である堎合、そのタむプは䜕ですか、そしおraiseは他のコンテキストで匏ずしお䜿甚できたすか それがステヌトメントである堎合、 raise以倖の堎合、そのセマンティクスは䜕ですか たたは、 or raiseを本質的に単䞀のステヌトメントにするこずを提案しおいたすかたずえば、 ::たたは=?代わりの構文ずしおor raise =? 

曞けたすか

defer f.Close() or raise(err2) errors.ReplaceIfNil(err, err2) or raise(err3) Transform(err3)



曞けたすか

f(r.Read(buf) or raise err)



defer f.Close() or raise(err2) errors.ReplaceIfNil(err, err2) or raise(err3) Transform(err3)

いいえ、2番目のraiseため、これは無効になりたす。 それがなかった堎合は、倉換チェヌン党䜓が実行され、最終結果が呌び出し元に返されるはずです。 党䜓ずしおそのようなセマンティクスはおそらく必芁ありたせんが、次のように曞くこずができたす。

defer f.Close() or raise(err2) Transform(errors.ReplaceIfNil(err, err2)


f(r.Read(buf) or raise err)

私の元のコメントを想定するず、巊偎の最埌の倀をずる、たたは取るので、デフォルト倀の堎合、最終的な匏は結果リストの残りの郚分に評䟡されたす。 はい、これは有効なはずです。 この堎合、 r.Readが゚ラヌを返すず、その゚ラヌが呌び出し元に返されたす。 それ以倖の堎合、 nはf枡されたす

線集

甚語に混乱しない限り、 orは二項挔算子だず思いたす。そのオペランドは同じタむプである必芁がありたすただし、巊偎のオペランドがリストである堎合は、少し魔法のようになりたす。その堎合、それは䞊蚘のリストの最埌の芁玠を取りたす。 raiseは、そのオペランドを取り、そのオペランドの倀を最埌の戻り匕数の倀ずしお䜿甚しお関数から戻る単項挔算子であり、前の匕数にはデフォルト倀がありたす。 次に、関数別名return ..., errから戻る目的で、スタンドアロンステヌトメントでraiseを技術的に䜿甚できたす。

これは理想的なケヌスですが、 or raiseは、ブロックではなく単玔なステヌトメントも受け入れる限り、 =?構文の代替ずしおも問題ありたせん。あたり冗長ではない方法でナヌスケヌスの倧郚分をカバヌしたす。 たたは、匏を受け入れるdeferのような文法を䜿甚するこずもできたす。 これは、次のようなケヌスの倧郚分をカバヌしたす。

f := os.Open("/some/file") or raise(err) errors.Wrap(err, "with context")

耇雑なケヌス

f := os.Open or raise(err) func() {
     if err == io.EOF {
         [
]
     }
  return err
}()

私の提案に぀いおもう少し考えお、私は共甚䜓/合蚈型に぀いお少し萜ずしおいたす。 私が提案しおいる構文は

guard [ ASSIGNMENT || EXPRESSION ] else { [ BLOCK ] }

匏の堎合、匏が評䟡され、結果がブヌル匏のtrueたたは他の匏の空癜倀ず等しくない堎合、BLOCKが実行されたす。 割り圓おでは、最埌に割り圓おられた倀が!= true / != nilに察しお評䟡されたす。 ガヌドステヌトメントに続いお、行われたすべおの割り圓おがスコヌプ内になりたす新しいブロックスコヌプは䜜成されたせん[おそらく最埌の倉数を陀いお]。

Swiftでは、 guardステヌトメントのBLOCKには、 return 、 break 、 continue 、たたはthrowいずれかが含たれおいる必芁がありたす。 私はそれが奜きかどうかは決めおいたせん。 読者はguardずいう単語から䜕が続くかを知っおいるので、それはある皋床の䟡倀を远加するようです。

guardがそのコミュニティによっお高く評䟡されおいるかどうかを蚀うのに十分なほどSwiftをフォロヌしおいる人はいたすか

䟋

guard f, err := os.Open("/some/file") else { return errors.Wrap(err, "could not open:") }

guard data, err := ioutil.ReadAll(f) else { return errors.Wrap(err, "could not read:") }

var obj interface{}

guard err = json.Unmarshal(data, &obj) else { return errors.Wrap(err, "could not unmarshal:") }

guard m, _ := obj.(map[string]interface{}) else { return errors.New("unexpected data format") }

guard val, _ := m["key"] else { return errors.New("missing key") }

私芋では、誰もが䞀床にここであたりにも広範囲の問題に぀いお話し合っおいたすが、実際の最も䞀般的なパタヌンは「そのたたの゚ラヌを返す」です。 では、次のようなsmthで最も問題に取り組みたせんか。

code, err ?= fn()

これは、関数がerr= nilで戻る必芁があるこずを意味したす。

=挔算子の堎合、導入できたすか=

code, err ?:= fn()

コンパむラは倉数「err」を同じ名前のerr戻り倀に枡す必芁があるため、=の状況はシャドりむングのために悪化しおいるようです。

間違ったコヌドを単に短くするのではなく、正しいコヌドを簡単に蚘述できるようにするこずに焊点を圓おおいる人がいるこずに、私は実際にかなり興奮しおいたす。

いく぀かのメモ

゚ラヌモデルに関するマむクロ゜フトのMidoriの蚭蚈者の1人からの興味深い「経隓レポヌト」 。

このドキュメントずSwiftのいく぀かのアむデアは、Go2に矎しく適甚できるず思いたす。

新しい再保存されたthrowsキヌワヌドを導入するず、関数は次のように定矩できたす。

func Get() []byte throws {
  if (...) {
    raise errors.New("oops")
  }

  return []byte{...}
}

別の非スロヌ関数からこの関数を呌び出そうずするず、未凊理のスロヌ可胜゚ラヌが原因でコンパむル゚ラヌが発生したす。
代わりに、䞀般的なケヌスであるこずに誰もが同意する゚ラヌを䌝播するか、それを凊理できる必芁がありたす。

func ScrapeDate() time.Time throws {
  body := Get() // compilation error, unhandled throwable
  body := try Get() // we've been explicit about potential throwable

  // ...
}

メ゜ッドが倱敗しないこずがわかっおいる堎合、たたはテストで、swiftず同様にtry!導入できたす。

func GetWillNotFail() time.Time {
  body := Get() // compilation error, throwable not handled
  body := try Get() // compilation error, throwable can not be propagated, because `GetWillNotFail` is not annotated with throws
  body := try! Get() // works, but will panic on throws != nil

  // ...
}

ただし、これらに぀いおはよくわかりたせんswiftず同様

func main() {
  // 1:
  do {
    fmt.Printf("%v", try ScrapeDate())
  } catch err { // err contains caught throwable
    // ...
  }

  // 2:
  do {
    fmt.Printf("%v", try ScrapeDate())
  } catch err.(type) { // similar to a switch statement
    case error:
      // ...
    case io.EOF
      // ...
  }
}

ps1。 耇数の戻り倀func ReadRune() (ch Rune, size int) throws { ... }
ps2。 return try Get()たたはreturn try! Get()戻るこずができたす
ps3。 buffer.NewBuffer(try Get())やbuffer.NewBuffer(try! Get())ような呌び出しをチェヌンできるようになりたした
ps4。 泚釈に぀いおよくわからない errors.Wrap(err, "context")を曞く簡単な方法
ps5。 これらは実際には䟋倖です
ps6。 最倧のメリットは、無芖された䟋倖のコンパむル時゚ラヌです。

あなたが曞いた提案は、すべおの悪いものず䞀緒にみどりリンクに正確に蚘述されおいたす
それの偎面...そしお「投げる」からの1぀の明癜な結果は「人々
嫌い」。ほずんどの堎合、毎回「スロヌ」ず曞く必芁があるのはなぜですか。
機胜

ずころで、゚ラヌを匷制的にチェックしお無芖しないずいう意図は、
゚ラヌ以倖のタむプにも適甚されたす。
䞀般化された圢匏䟋gcc __attribute __warn_unused_result。

挔算子の圢匏に぀いおは、短い圢匏たたは
このようなキヌワヌドフォヌム

= fnたたはfnをチェックしたす-呌び出し元に゚ラヌを䌝播したす
= fnたたはnofail fn-゚ラヌ時にパニック

12:15時土、2017幎8月26日には、nvartolomei [email protected]
曞きたした

いく぀かのメモ

面癜い䜓隓レポヌト
http://joeduffyblog.com/2016/02/07/the-error-model/から
゚ラヌモデルに関するMicrosoftのMidoriの蚭蚈者。

このドキュメントずSwiftからいく぀かのアむデアがあるず思いたす
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/ErrorHandling.html
Go2に矎しく適甚できたす。

新しい再保存されたthrowsキヌワヌドを導入するず、関数は次のように定矩できたす。

func Get[] byte throws {
もしも ... {
゚ラヌを発生させたす。New "oops"
}

[] byte {...}を返したす
}

この関数を別の非スロヌ関数から呌び出そうずするず、
未凊理のスロヌ可胜な゚ラヌが原因で、コンパむル゚ラヌが発生したす。
代わりに、゚ラヌを䌝播できるはずです。これは誰もが同意するものです。
䞀般的なケヌス、たたはそれを凊理したす。

func ScrapeDatetime.Time throws {
body= Get//コンパむル゚ラヌ、未凊理のスロヌ可胜
body= try Get//スロヌ可胜な可胜性に぀いお明瀺したした

//..。
}

メ゜ッドが倱敗しないこずがわかっおいる堎合、たたはテストでは、次のこずができたす。
玹介しおみおください スむフトに䌌おいたす。

func GetWillNotFailtime.Time {
body= Get//コンパむル゚ラヌ、スロヌ可胜は凊理されたせん
body= try Get//コンパむル゚ラヌ。 GetWillNotFailはthrowsの泚釈が付いおいないため、throwableを䌝播できたせん。
body=詊しおみおください Get//動䜜したすが、スロヌするずパニックになりたす= nil

//..。
}

ただし、これらに぀いおはよくわかりたせんswiftず同様

func main{
// 1
行う {
fmt.Printf "v"、ScrapeDateを詊しおください
} catch err {// errにはキャッチされたthrowableが含たれおいたす
//..。
}

// 2
行う {
fmt.Printf "v"、ScrapeDateを詊しおください
} catch err。type{// switchステヌトメントに䌌おいたす
ケヌス゚ラヌ
//..。
ケヌスio.EOF
//..。
}
}

ps1。 耇数の戻り倀funcReadRunech Rune、size intthrows {
...}
ps2。 return try Getたたはreturn tryで戻るこずができたす 取埗する
ps3。 これで、buffer.NewBuffertry Getやbuffer.NewBuffertry
取埗する
ps4。 泚釈に぀いおよくわからない

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

@jbaず@bcmillsによっお提案された挔算子は、「??」ず綎る方が適切ですが、非垞に優れたアむデアだず思いたす。 「=」の代わりに IMO。

この䟋を芋おください

func doStuff() (int,error) {
    x, err := f() 
    if err != nil {
        return 0, wrapError("f failed", err)
    }

    y, err := g(x)
    if err != nil {
        return 0, wrapError("g failed", err)
    }

    return y, nil
}

func doStuff2() (int,error) {
    x := f()  ?? (err error) { return 0, wrapError("f failed", err) }
    y := g(x) ?? (err error) { return 0, wrapError("g failed", err) }
    return y, nil
}

doStuff2は、次の理由により、かなり読みやすく、すばやく読むこずができるず思いたす。

  1. 垂盎方向のスペヌスの無駄が少ない
  2. 巊偎の幞せな道をすばやく読みやすい
  3. 右偎の゚ラヌ状態をすばやく読み取るのは簡単です
  4. 関数のロヌカル名前空間を汚染するerr倉数はありたせん

私には、この提案だけでは䞍完党に芋え、魔法が倚すぎたす。 ??挔算子はどのように定矩されたすか 「nilでない堎合、最埌の戻り倀をキャプチャしたす」 「メ゜ッドタむプに䞀臎する堎合、最埌の゚ラヌ倀をキャプチャしたすか」

䜍眮ずタむプに基づいお戻り倀を凊理するための新しい挔算子を远加するこずは、ハックのように芋えたす。

2017幎8月29日、午前13時03分0300、ミカ゚ル・グスタフ[email protected] 、曞きたした

@jbaず@bcmillsによっお提案された挔算子は、「??」ず綎る方が適切ですが、非垞に優れたアむデアだず思いたす。 「=」の代わりに IMO。
この䟋を芋おください
func doStuffint、error{
x、err= f
err= nil {の堎合
0を返し、wrapError "f failed"、err
}

   y, err := g(x)
   if err != nil {
           return 0, wrapError("g failed", err)
   }

   return y, nil

}

func doStuff2int、error{
x= f?? ゚ラヌ゚ラヌ{return 0、wrapError "f failed"、err}
y= gx?? ゚ラヌ゚ラヌ{return 0、wrapError "g failed"、err}
y、nilを返す
}
doStuff2は、次の理由により、かなり読みやすく、すばやく読むこずができるず思いたす。

  1. 垂盎方向のスペヌスの無駄が少ない
  2. 巊偎の幞せな道をすばやく読みやすい
  3. 右偎の゚ラヌ状態をすばやく読み取るのは簡単です
  4. 関数のロヌカル名前空間を汚染するerr倉数はありたせん

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

@nvartolomei

??挔算子はどのように定矩されたすか

https://github.com/golang/go/issues/21161#issuecomment-319434101およびhttps://github.com/golang/go/issues/21161#issuecomment-320758279を参照しおください。

@bcmillsは静止スレッドを埩掻させるこずを掚奚しおいるので、他の蚀語からのクリブを怜蚎する堎合、ステヌトメント修食子はこれらすべおに合理的な解決策を提䟛するようです。 @slvmndの䟋をずるには、ステヌトメント修食子を䜿甚しおやり盎したす。

func doStuff() (int, err) {
        x, err := f()
        return 0, wrapError("f failed", err)     if err != nil

    y, err := g(x)
        return 0, wrapError("g failed", err)     if err != nil

        return y, nil
}

ステヌトメントず゚ラヌチェックを1行で行うほど簡朔ではありたせんが、かなりよく読みたす。 if匏で=圢匏の割り圓おを蚱可しないこずをお勧めしたす。そうしないず、文法が明確であっおも、スコヌプの問題によっお人々が混乱する可胜性がありたす「if」の吊定バヌゞョンずしお「unless」を蚱可するのは少しです構文糖衣ですが、読むずうたく機胜し、怜蚎する䟡倀がありたす。

ただし、ここでPerlからクリブするこずはお勧めしたせん。 Basic Plus 2は問題ありたせんそのように、ステヌトメント修食子をルヌプしたす。これは、䟿利な堎合もありたすが、かなり耇雑な問題の別のセットをもたらしたす。

短いバヌゞョン
err= nilの堎合に戻る
その堎合もサポヌトする必芁がありたす。

このような構文では、疑問が生じたす-非戻りステヌトメントも必芁です
次のような「if」ステヌトメントでサポヌトされたす。
funcargsif条件

おそらくアフタヌアクションを発明する代わりに-シングルを導入する䟡倀がある堎合
の堎合の行

err= nilreturnの堎合
err= nilが0を返す堎合、wrapError "failed"、err
err= nil do_smthの堎合

特別な圢匏の構文よりもはるかに自然なようですよね たぶん
構文解析に倚くの苊痛をもたらしたす/

しかし...それはすべお小さな調敎であり、゚ラヌに察する特別なlangサポヌトではありたせん
取り扱い/䌝播。

16:14時月、2017幎9月18日には、dsugalski [email protected]は曞きたした

@bcmills https://github.com/bcmillsが埩掻するこずを掚奚しおいるので、
静止スレッド、他の蚀語からのクリブを怜蚎する堎合は、
ステヌトメント修食子はすべおの人に合理的な解決策を提䟛するようです
これ。 @slvmnd https://github.com/slvmndの䟋をずるには、次のようにやり盎したす。
ステヌトメント修食子

func doStuffint、err{
x、err= f
err= nilの堎合、0を返し、wrapError "f failed"、err

  y, err := g(x)
    return 0, wrapError("g failed", err)     if err != nil

    return y, nil

}

ステヌトメントず゚ラヌチェックを1぀にたずめるほど簡朔ではありたせん
行ですが、それはかなりよく読みたす。 =圢匏のを犁止するこずをお勧めしたす
if匏での割り圓お、そうでない堎合、スコヌプの問題が発生する可胜性がありたす
文法がはっきりしおいおも人を混乱させる
「if」の吊定バヌゞョンは少し構文糖衣ですが、
読んで、怜蚎する䟡倀がありたす。

ただし、ここでPerlからクリブするこずはお勧めしたせん。 Basic Plus2は
现かいそのようにルヌプステヌトメント修食子がありたすが、
䟿利です。かなり耇雑な問題の別のセットを持ち蟌んでください。

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

@dsugalskiの提案に぀いおみるず、

玔粋なテキストからどれだけの芖芚的な区別を期埅するのが合理的かはわかりたせん。 ある時点で、それをテキスト゚ディタのIDEたたはコヌドカラヌリングレむダヌにパントする方が適切だず思われたす。

しかし、テキストベヌスの芖芚的な区別のために、私がこれを恥ずかしいほど昔に䜿い始めたずきに私たちが持っおいたフォヌマット暙準は、IF / UNLESSステヌトメント修食子を右寄せする必芁があり、それによっお十分に目立぀ようになりたした。 ただし、VT-220端末では、りィンドりサむズがより柔軟な゚ディタヌよりも、適甚が容易で、おそらく芖芚的に区別できる暙準が付䞎されおいたす

少なくずも私にずっおは、ステヌトメント修食子のケヌスは簡単に区別でき、珟圚のif-blockスキヌムよりも読みやすくなっおいたす。 もちろん、これは他の人には圓おはたらないかもしれたせん。私は英語のテキストを読むのず同じ方法で゜ヌスコヌドを読むので、既存の快適なパタヌンにマッピングされたすが、誰もがこれを行うわけではありたせん。

return 0, wrapError("f failed", err) if err != nilはif err != nil { return 0, wrapError("f failed", err) }ず曞くこずができたす

if err != nil return 0, wrapError("f failed", err)も同じように曞くこずができたす。

たぶん、ここで必芁なのは、gofmtがifを3行に拡匵するのではなく、1行に1行で曞いたたたにするこずだけですか

私を襲う別の可胜性がありたす。 䜿い捚おのGoコヌドをすばやく曞き蟌もうずしたずきに経隓する倚くの摩擊は、すべおの呌び出しで゚ラヌチェックを行う必芁があるため、呌び出しを適切にネストできないためです。

たずえば、最初にhttp.NewRequestの結果を䞀時倉数に割り圓おおから、その䞊でDoを呌び出さずに、新しい芁求オブゞェクトでhttp.Client.Doを呌び出すこずはできたせん。

私たちは蚱可できるかどうか疑問に思いたす

f(y())

yが(T, error)タプルを返しおも機胜したす。 yが゚ラヌを返すず、コンパむラは匏の評䟡を䞭止し、その゚ラヌをfから返す可胜性がありたす。 fが゚ラヌを返さない堎合は、゚ラヌが返される可胜性がありたす。

それから私はするこずができたした

n, err := http.DefaultClient.Do(http.NewRequest("DELETE", "/foo", nil))

NewRequestたたはDoのいずれかが倱敗した堎合、゚ラヌ結果はnil以倖になりたす。

ただし、これには1぀の重倧な問題がありたす。぀たり、fが2぀の匕数、たたは可倉個匕数を受け入れる堎合、䞊蚘の匏はすでに有効です。 たた、これを行うための正確なルヌルはかなり耇雑になる可胜性がありたす。

したがっお、䞀般的に、私はそれが奜きではないず思いたすこのスレッドの他の提案にも熱心ではありたせんが、ずにかく怜蚎のためにアむデアを捚おるず思いたした。

@rogpeppeたたはあなただけ䜿甚するこずができたすjson.NewEncoderを

@gbbrはい、悪い䟋です。

より良い䟋はhttp.Requestかもしれたせん。 それを䜿甚するようにコメントを倉曎したした。

わお。 倚くのアむデアがコヌドの可読性をさらに悪化させおいたす。
私はアプロヌチで倧䞈倫です

if val, err := DoMethod(); err != nil {
   // val is accessible only here
   // some code
}

本圓に厄介なのは、返された倉数のスコヌプです。
この堎合、 valを䜿甚する必芁がありたすが、範囲はifです。
したがっお、 elseを䜿甚する必芁がありたすが、リンタヌはそれに反察したすそしお私も。

val, err := DoMethod()
if err != nil {
   // some code
}
// some code with val

ifブロック倖の倉数にアクセスできるず䟿利です。

if val, err := DoMethod(); err != nil {
   // some code
}
// some code with val

@dmbreakerこれが、基本的にSwiftのガヌド句の目的です。 䜕らかの条件を通過した堎合、珟圚のスコヌプ内の倉数を割り圓おたす。 私の以前のコメントを参照し

私はGoでの゚ラヌ凊理を単玔化するこずに党力を泚いでいたすが個人的にはそれほど気にしたせんが、これにより、他の点では単玔で非垞に読みやすい蚀語に少し魔法がかかるず思いたす。

@gbbr
ここで蚀及しおいる「これ」ずは䜕ですか 物事を進める方法に぀いおは、かなりの数の異なる提案がありたす。

おそらく2぀の郚分からなる解決策ですか

tryを「戻りタプルの右端の倀をはがしたす。その型のれロ倀でない堎合は、他の倀をれロに蚭定しお、この関数の右端の倀ずしお返したす」ず定矩したす。 これは䞀般的なケヌスになりたす

 a := try ErrorableFunction(b)

連鎖を可胜にしたす

 a := try ErrorableFunction(try SomeOther(b, c))

オプションで、効率を䞊げるために、れロ以倖ではなくれロ以倖にしたす。゚ラヌ関数がれロ以倖/れロ以倖を返す堎合、関数は「倀で䞭止」したす。 try 'ed関数の右端の倀は、呌び出し元の関数の右端の倀に割り圓お可胜である必芁がありたす。そうしないず、コンパむル時の型チェック゚ラヌになりたす。 したがっお、これはerrorのみを凊理するようにハヌドコヌディングされおいたせんが、おそらくコミュニティは他の「賢い」コヌドの䜿甚を掚奚しないはずです。

次に、次のいずれかのdeferのようなキヌワヌドでtryreturnsをキャッチできるようにしたす。

catch func(e error) {
    // whatever this function returns will be returned instead
}

たたは、もっず倧雑把に蚀えば、Goがすでにどのように機胜しおいるかにもっず䞀臎しおいたす。

defer func() {
    if err := catch(); err != nil {
        set_catch(ErrorWrapper{a, "while posting request to server"})
    }
}()

catch堎合、関数のパラメヌタヌは返される倀ず正確に䞀臎する必芁がありたす。 耇数の関数が提䟛されおいる堎合、倀はそれらすべおを逆の順序で通過したす。 もちろん、正しいタむプの関数に解決される倀を入れるこずができたす。 deferベヌスの䟋の堎合、1぀のdefer関数がset_catch呌び出すず、次の延期関数はそれをcatch()倀ずしお取埗したす。 プロセスでnilに戻すのに十分愚かである堎合は、玛らわしい戻り倀が出力されたす。そうしないでください。set_catchに枡される倀は、返される型に割り圓お可胜である必芁がありたす。 どちらの堎合も、これは宣蚀ではなくステヌトメントであり、ステヌトメントの実行埌にのみコヌドに適甚されるずいう点で、これがdeferように機胜するこずを期埅しおいたす。

私は単玔さの芳点から延期ベヌスの゜リュヌションを奜む傟向がありたす基本的に新しい抂念は導入されおいたせん。新しいものではなく、2番目のタむプのrecover()ですが、パフォヌマンスの問題がある可胜性があるこずを認めたす。 個別のcatchキヌワヌドを䜿甚するず、通垞のリタヌンが発生したずきに完党にスキップしやすくなるため、効率が向䞊する可胜性がありたす。最倧の効率を実珟したい堎合は、スコヌプたたは関数ごずに1぀だけがアクティブになるように、スコヌプに関連付けたす。 、これはほがれロコストだず思いたす。 おそらく、゜ヌスコヌドファむル名ず行番号もcatch関数から返される必芁がありたすかコンパむル時にそれを行うのは安䟡であり、人々が今フルスタックトレヌスを芁求する理由のいく぀かをかわすでしょう。

どちらも、繰り返しの゚ラヌ凊理を関数内の1぀の堎所で効果的に凊理できるようにし、゚ラヌ凊理をラむブラリ関数ずしお簡単に提䟛できるようにしたす。これは、䞊蚘のrscのコメントによるず、珟圚のケヌスの最悪の偎面の1぀です。 ゚ラヌ凊理の面倒さは、正しい凊理ではなく「returnerr」を助長する傟向がありたす。 私はそれず自分自身で倚くの苊劎をしおいるこずを知っおいたす。

@thejerfこの提案に関するIanのポむントの䞀郚は、関数がコンテキストを远加したり、返された゚ラヌを操䜜したりするこずを思いずどたらせるこずなく、゚ラヌの定型文に察凊する方法を探るこずです。

゚ラヌ凊理をtryずcatch分けるず、その目暙に反するように芋えたすが、プログラムが通垞远加する詳现の皮類によっお異なりたす。

少なくずも、より珟実的な䟋でどのように機胜するかを確認したいず思いたす。

私の提案の党䜓的なポむントは、コンテキストを远加したり、゚ラヌを操䜜したりできるようにするこずです。これは、そのコンテキストを䜕床も繰り返すこずを含むここでのほずんどの提案よりもプログラム的に正しいず考える方法であり、それ自䜓が远加のコンテキストを入れたいずいう欲求を劚げたす。 。

元の䟋を曞き盎すには、

func Chdir(dir string) error {
    if e := syscall.Chdir(dir); e != nil {
        return &PathError{"chdir", dir, e}
    }
    return nil
}

ずしお出おきたす

func Chdir(dir string) error {
    catch func(e error) {
        return &PathError{"chdir", dir, e}
    }

    try syscall.Chdir(dir)
    return nil
}

ただし、この䟋は、実際にはこれらの提案のいずれにも取るに足らないものであり、この堎合は、元の関数をそのたたにしおおくず思いたす。

個人的には、そもそも元のChdir関数が問題だずは思っおいたせん。 私はこれを特に調敎しお、1぀の゚ラヌ関数ではなく、長時間繰り返される゚ラヌ凊理によっお関数にノむズが発生する堎合に察凊しおいたす。 たた、考えられるすべおのナヌスケヌスで文字通り異なるこずを行う関数がある堎合、正しい答えはおそらく、すでに埗たものを曞き続けるこずだず思いたす。 しかし、それが䞀般的なケヌスであったずしおも、そもそも苊情はないずいう理由で、ほずんどの人にずっおこれは非垞にたれなケヌスだず思いたす。 ゚ラヌをチェックするノむズは、関数内で「ほが同じこず」を䜕床も繰り返したいずいう理由だけで重芁です。

私はたた、人々が望んでいるもののほずんどが満たされるだろうず思いたす

func SomethingBigger(dir string) (interface{}, error) {
     catch func (e error, filename string, lineno int) {
         return PackageSpecificError{e, filename, lineno, dir}
     }

     x := try Something()

     if x == true {
         try SomethingElse()
     } else {
         a, b = try AThirdThing()
     }

     return whatever, nil
}

小さすぎお気にしないずいう理由で単䞀のifステヌトメントの芋栄えを良くしようずする問題を取り陀き、゚ラヌが返されるたびに本圓にナニヌクなこずをしおいる関数の問題を取り陀きたす。 これは実際にはかなりたれなケヌスであり、Bその堎合、ボむラヌプレヌトのオヌバヌヘッドは、固有の凊理コヌドの耇雑さに察しお実際にはそれほど重芁ではありたせん。おそらく、問題は解決策のあるものに枛らすこずができたす。

私も本圓に芋たいです

func packageSpecificHandler(f string) func (err error, filename string, lineno int) {
    return func (err error, filename string, lineno int) {
        return &PackageSpecificError{"In function " + f, err, filename, lineno}
    }
}

 func SomethingBigger(dir string) (interface{}, error) {
     catch packageSpecificHandler("SomethingBigger")

     ...
 }

たたは、それが機胜する堎合は、同等のものが可胜です。

そしお、ペヌゞ䞊のすべおの提案の䞭で...これはただGoのように芋えたせんか 珟圚のGoよりもGoのように芋えたす。

正盎なずころ、私の専門的な゚ンゞニアリング経隓のほずんどはPHP私は知っおいたすでしたが、Goの䞻な魅力は垞に読みやすさでした。 私はPHPのいく぀かの偎面を楜しんでいたすが、私が最も軜蔑しおいるのは、「最終的な」「抜象的な」「静的な」ナンセンスであり、1぀のこずを行うコヌドに過床に耇雑な抂念を適甚するこずです。

この提案を芋るず、ある郚分を芋お、ダブルテむクを実行し、そのコヌドの郚分が䜕を蚀っおいるのか、たたは䜕をしおいるのかを本圓に「考え」なければならないずいう感芚にすぐに逆戻りしたした。 私はこのコヌドが読みやすく、実際に蚀語に远加されるずは思いたせん。 私の最初の本胜は巊偎を芋るこずであり、これは垞にnil返すず思いたす。 ただし、この倉曎により、コヌドの動䜜を刀断するために、巊右を芋る必芁がありたす。これは、より倚くの時間を読んで、より倚くのメンタルモデルを意味したす。

ただし、これはGoでの゚ラヌ凊理を改善する䜙地がないこずを意味するものではありたせん。

申し蚳ありたせんが、このスレッド党䜓をただ読んでいたせん非垞に長いですが、人々が別の構文を投げおいるのを芋るので、私の考えを共有したいず思いたす

a, err := helloWorld(); err? {
  return fmt.Errorf("helloWorld failed with %s", err)
}

これを無効にする䞊蚘の䜕かを芋逃しおいないこずを願っおいたす。 私はい぀かすべおのコメントを通り抜けるこずを玄束したす:)

型倉換のセマンティックの混乱を避けるために、挔算子はerror型でのみ蚱可される必芁があるず私は信じおいたす。

興味深い、 @ buchanae 、しかしそれは私たちをはるかに乗り越えたすか

if a, err := helloWorld(); err != nil {
  return fmt.Errorf("helloWorld failed with %s", err)
}

aを゚スケヌプできるのは確かですが、珟圚の状態では、スコヌプはthenブロックずelseブロックになりたす。

@ object88そうです、倉化は埮劙で、矎的で、䞻芳的です。 個人的には、このトピックに関しおGo 2に求めおいるのは、読みやすさの埮劙な倉曎だけです。

個人的には、行がif始たっおおらず、 !=nil必芁ずしないため、読みやすくなっおいたす。 倉数は、ほずんど他の行にある巊端にありたす。

aの範囲の玠晎らしい点、私はそれを考慮しおいたせんでした。

この文法の他の可胜性を考えるず、これは可胜であるように思われたす。

err := helloWorld(); err? {
  return fmt.Errorf("error: %s", err)
}

そしおおそらく

helloWorld()? {
  return fmt.Errorf("hello world failed")
}

倚分それがバラバラになるずころです。

たぶん、゚ラヌを返すこずはGoのすべおの関数呌び出しの䞀郚であるはずなので、次のこずを想像できたす。
`` `
a= helloWorld; え {{
fmt.Errorf "helloWorld faileds"、errを返したす
}

実際の䟋倖凊理はどうですか ぀たり、詊しお、キャッチしお、最終的には倚くの珟代語のように

いいえ、コヌドが暗黙的で䞍明確になりたすただし、実際には少し短くなりたす

7時27分に朚、2017幎11月23日には、Kamyar Miremadi [email protected]
曞きたした

実際の䟋倖凊理はどうですか ぀たり、詊しお、キャッチしお、最埌に
代わりに倚くの珟代語のように

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

@mpvlのWriteToGCSの䟋のアップスレッドに戻っお、コミット/ロヌルバックパタヌンは、Goの゚ラヌ凊理の倧幅な倉曎を保蚌するほど䞀般的ではないこずを再床提案したいず思いたす。 関数遊び堎リンクでパタヌンをキャプチャするのは難しくありたせん

func runWithCommit(f, commit func() error, rollback func(error)) (err error) {
    defer func() {
        if r := recover(); r != nil {
            rollback(fmt.Errorf("panic: %v", r))
            panic(r)
        }
    }()
    if err := f(); err != nil {
        rollback(err)
        return err
    }
    return commit()
}

次に、䟋を次のように蚘述できたす。

func writeToGCS(ctx context.Context, bucket, dst string, r io.Reader) error {
    client, err := storage.NewClient(ctx)
    if err != nil {
        return err
    }
    defer client.Close()

    w := client.Bucket(bucket).Object(dst).NewWriter(ctx)
    return runWithCommit(
        func() error { _, err := io.Copy(w, r); return err },
        func() error { return w.Close() },
        func(err error) { _ = w.CloseWithError(err) })
}

私はより簡単な解決策を提案したす

func someFunc() error {
    ^err := someAction()
    ....
}

耇数の耇数の関数が返される堎合

func someFunc() error {
    result, ^err := someAction()
    ....
}

そしお、耇数の戻り匕数の堎合

func someFunc() (result Result, err error) {
    var result Result
    params, ^err := someAction()
    ....
}

^蚘号は、パラメヌタヌがnilでない堎合に戻るこずを意味したす。
基本的に「゚ラヌが発生した堎合はスタックを䞊に移動する」

この方法の欠点はありたすか

@gladkikhartem
゚ラヌが返される前に、どのように゚ラヌを倉曎したすか

@urandom
゚ラヌのラップは重芁なアクションであり、私の意芋では明瀺的に実行する必芁がありたす。
Goコヌドは読みやすさに関するものであり、魔法ではありたせん。
゚ラヌラッピングをより明確にしたいず思いたす

しかし同時に、倚くの情報を運ばず、スペヌスをずるだけのコヌドを取り陀きたいず思いたす。

if err != nil {
    return err
}

それは囲碁の決たり文句のようなものです-あなたはそれを読みたくない、あなたはただそれをスキップしたいのです。

この議論でこれたでに芋たのは、次の組み合わせです。

  1. 構文の冗長性を枛らす
  2. コンテキストを远加しお゚ラヌを改善する

これは、䞡方の偎面に蚀及しおいる@ianlancetaylorによる元の問題の説明ず

1.構文の冗長性の削枛

@gladkikhartemのアむデアは、線集/拡匵されおからここで報告する元の圢匏でも

 result, ^ := someAction()

funcのコンテキストでは

func getOddResult() (int, error) {
    result, ^ := someResult()
    if result % 2 == 0 {
          return result + 1, nil
    }
    return result, nil
}

この短い構文たたは@gladkikhartemによっおerr^提案された圢匏は、問題の構文の冗長性の郚分に察凊したす1。

2.゚ラヌコンテキスト

2番目の郚分では、コンテキストを远加するこずで、今のずころ完党に忘れるこずができたす。埌で、特別なcontextErrorタむプが䜿甚されおいる堎合、各゚ラヌにスタックトレヌスを自動的に远加するこずを提案したす。 このような新しいネむティブ゚ラヌタむプは、完党たたは短いスタックトレヌス GO_CONTEXT_ERROR=full想像しおくださいを備え、 errorむンタヌフェむスず互換性があり、最䞊䜍の呌び出しスタックから少なくずも関数ずファむル名を抜出する可胜性を提䟛したす。゚ントリ。

contextErrorを䜿甚する堎合、どういうわけかGoは、゚ラヌが䜜成された正確なポむントに呌び出しスタックトレヌスをアタッチする必芁がありたす。

再びfuncの䟋で

func getOddResult() (int, contextError) {
    result, ^ := someResult() // here a 'contextError' is created; if the error received from 'someResult()' is also a `contextError`, the two are nested
    if result % 2 == 0 {
          return result + 1, nil
    }
    return result, nil
}

タむプのみがerrorからcontextErrorに倉曎されたした。これは、次のように定矩できたす。

type contextError interface {
    error
    Stack() []StackEntry
    Cause() contextError
}

このStack()がhttps://golang.org/pkg/runtime/debug/#Stackずどのように異なるかに泚意しおください。これは、バむト以倖のバヌゞョンのgoroutine呌び出しスタックがここにあるこずを望んでいるためです

Cause()メ゜ッドは、ネストの結果ずしおnilたたは前のcontextErrorを返したす。

私は、このようなスタックを持ち歩くこずの朜圚的なメモリぞの圱響をよく知っおいるので、1぀たたは少数の゚ントリしか含たないデフォルトの短いスタックを持぀可胜性を瀺唆したした。 開発者は通垞、開発/デバッグバヌゞョンで完党なstracktraceを有効にし、それ以倖の堎合はデフォルト短いスタックトレヌスのたたにしたす。

先行技術

  • https://godoc.org/github.com/pkg/errors このパッケヌゞを詳しく知らないか、モデル化する必芁があるこずを瀺唆しおいたすが、最も䜿甚されおいる/既知のパッケヌゞの1぀です

ただ考えるための食べ物。

@gladkikhartem @ gdm85

あなたはこの提案の芁点を芋逃したず思いたす。 むアンの元の投皿によるず

゚ラヌを無芖するこずはすでに簡単ですおそらく簡単すぎたす20803を参照。 ゚ラヌ凊理に関する既存の提案の倚くは、倉曎せずに゚ラヌを返すのを容易にしたすたずえば、16225、18721、21146、21155。 远加情報を䜿甚しお゚ラヌを簡単に返すこずができるものはほずんどありたせん。

倉曎せずに゚ラヌを返すこずはしばしば間違っおおり、通垞は少なくずも圹に立たない。 泚意深い゚ラヌ凊理を奚励したいず思いたす。「倉曎されおいないリタヌン」のナヌスケヌスのみに察凊するず、むンセンティブが間違った方向にバむアスされたす。

@bcmillsコンテキストスタックトレヌスの圢匏が远加されおいる堎合、゚ラヌは远加情報ずずもに返されたす。 「レコヌド挿入䞭の゚ラヌ」などの人間が読めるメッセヌゞを添付するこずは、「泚意深い゚ラヌ凊理」ず芋なされたすか コヌルスタックのどの時点でそのようなメッセヌゞを远加する必芁があるかを決定するにはどうすればよいですか各関数、トップ/ボトムなど これらはすべお、コヌディング゚ラヌ凊理の改善に関する䞀般的な質問です。

「returnunmodified」は、デフォルトで「return unmodified with stacktrace」を䜿甚しお䞊蚘で説明したように打ち消すこずができ、リアクティブスタむルで必芁に応じお人間が読めるメッセヌゞを远加したす。 このような人間が読めるメッセヌゞを远加する方法は指定しおいたせんが、いく぀かのアむデアに぀いおは、 pkg/errorsでラッピングがどのように機胜するかを確認できたす。

「倉曎せずに゚ラヌを返すこずはしばしば間違っおいたす」したがっお、私は怠惰なナヌスケヌスのアップグレヌドパスを提案したす。これは、珟圚有害であるず指摘されおいるのず同じナヌスケヌスです。

@bcmills
私は20803に100同意したす。゚ラヌは垞に凊理するか、明瀺的に無芖する必芁がありたすそしお、なぜこれが以前に行われなかったのかわかりたせん...
はい、私は提案のポむントに察凊したせんでした、そしお私はそうする必芁はありたせん。 意図は結果ず䞀臎しないため、背埌にある意図ではなく、提案された実際の解決策に関心がありたす。 そしお私が芋るずき|| そのような|| 提案されおいるもの-それは私を本圓に悲しくさせたす。

゚ラヌコヌドや゚ラヌメッセヌゞなどの情報を゚ラヌに埋め蟌むのが簡単で透過的である堎合慎重な゚ラヌ凊理を奚励する必芁はありたせん、人々はそれを自分で行いたす。
たずえば、゚ラヌを゚むリアスにしたす。 あらゆる皮類のものを返し、キャストせずに関数の倖で䜿甚するこずができたす。 人生をずおも楜にしおくれるでしょう。

Goが゚ラヌを凊理するように私に思い出させるのは奜きですが、デザむンが私に疑わしいこずをするように勧めるずきは嫌いです。

@ gdm85
゚ラヌにスタックトレヌスを自動的に远加するのはひどい考えです。Javaスタックトレヌスを芋おください。
゚ラヌを自分でラップするず、䜕が問題になっおいるのかをナビゲヌトしお理解するのがはるかに簡単になりたす。 それがそれを包むこずの党䜓的なポむントです。

@gladkikhartem私は、「自動ラッピング」の圢匏がナビゲヌトし、䜕が悪いのかを理解するのを助けるのにはるかに悪いだろうずいうこずに同意し

Goのベストプラクティス倚かれ少なかれ暙準的である可胜性がありたすの理解を深めるこずず、そのような定矩が珟圚の状況からの改善に向けた提案を行うための鍵になるず思うので、䞡方にお願いしたす。

@gladkikhartemこの提案はすでにif err != nil { return err }単玔化するこずに関するいく぀かの異なる提案がすでにあり、それらはその特定のケヌスを改善するだけの構文を議論する堎所です。 ありがずう。

@ianlancetaylor
議論を邪魔にならないように動かしおしたったらごめんなさい。

゚ラヌにコンテキスト情報を远加する堎合は、次の構文を䜿甚するこずをお勧めしたす。
そしお、コンテキスト抜出を容易にするために、1぀の関数に察しお1぀の゚ラヌタむプのみを䜿甚するように人々に匷制したす

type MyError struct {
    Type int
    Message string
    Context string
    Err error
}

func VeryLongFunc() error {
    var err MyError
    err.Context = "general function context"


   result, ^err.Err := someAction() {
       err.Type = PermissionError
       err.Message = fmt.SPrintf("some action has no right to access file %v: ", file)
   }

    // in case we need to make a cleanup after error

   result, ^err.Err := someAction() {
       err.Type = PermissionError
       err.Message = fmt.SPrintf("some action has no right to access file %v: ", file)
       file.Close()
   }

   // another variant with different symbol and return statement

   result, ?err.Err := someAction() {
       err.Type = PermissionError
       err.Message = fmt.SPrintf("some action has no right to access file %v: ", file)
       return err
   }

   // using original approach

   result, err.Err := someAction()
   if err != nil {
       err.Type = PermissionError
       err.Message = fmt.SPrintf("some action has no right to access file %v: ", file)
       return err
   }
}

func main() {
    err := VeryLongFunc()
    if err != nil {
        e := err.(MyError)
        log.Print(e.Error(), " in ", e.Dir)
    }
}

^蚘号は、゚ラヌパラメヌタを瀺し、関数定矩ず「someAction{}」の゚ラヌ凊理を区別するために䜿甚されたす。
゚ラヌが倉曎されずに返された堎合は、{}を省略できたす

「泚意深い゚ラヌ凊理」をより適切に定矩するために、私自身の招埅に返信するためのリ゜ヌスをさらに远加したす。

珟圚のアプロヌチず同じくらい退屈ですが、ステヌトメントが機胜する可胜性がある堎合は1行ですが、他のアプロヌチよりも混乱が少ないず思いたす。 倚分

blah, err := doSomething()
if err != nil: return err

...あるいは...

blah, err := doSomething()
if err != nil: return &BlahError{"Something",err}

誰かがすでにこれを提起したかもしれたせんが、たくさんの投皿があり、私はそれらの倚くを読みたしたが、すべおではありたせん。 ずはいえ、個人的には、暗黙的であるよりも明瀺的である方が良いず思いたす。

私は鉄道指向プログラミングのファンでした。アむデアはElixirのwithステヌトメントから来おいたす。
elseブロックは、 e == nil短絡するず実行されたす。

これが、擬䌌コヌドを先に眮いた私の提案です。

func Chdir(dir string) (e error) {
    with e == nil {
            e = syscall.Chdir(dir)
            e, val := foo()
            val = val + 1
            // something else
       } else {
           printf("e is not nil")
           return
       }
       return nil
}

@ardhitamaこれは、「With」が「Try」ステヌトメントのようなものであり、「Else」が「C​​atch」のようなものであるこずを陀いお、
JavaやCのような䟋倖凊理を実装しおみたせんか
プログラマヌがその関数で䟋倖を凊理したくない堎合は、その関数の結果ずしお䟋倖を返したす。 それでも、プログラマヌが望たない堎合に䟋倖を凊理するように匷制する方法はなく、倚くの堎合、本圓に必芁はありたせんが、ここで埗られるのは、コヌドを醜くするif err= nilステヌトメントです。読み取り䞍胜ノむズが倚い。 そもそも他のプログラミング蚀語でTryCatchFinallyステヌトメントが発明されたのはそれが理由ではないでしょうか。

ですから、Go Authorsが頑固にならないように「やっおみお」ください 次のバヌゞョンでは、「TryCatchFinally」ステヌトメントを導入するだけです。 ありがずう。

@KamyarM
Goには䟋倖がないため、goに䟋倖凊理を導入するこずはできたせん。
Goでtry {} catch {}を導入するこずは、Cでtry {} catch {}を導入するこずに䌌それはたったく間違っおいたす。

@ianlancetaylor
Goの゚ラヌ凊理をたったく倉曎せずに、このようなgofmtツヌルを1行の゚ラヌ凊理に倉曎するのはどうでしょうか。

err := syscall.Chdir(dir)
    if err != nil {return &PathError{"chdir", dir, err}}
err = syscall.Chdir(dir2)
    if err != nil {return err}

䞋䜍互換性があり、珟圚のプロゞェクトに適甚できたす

䟋倖は装食されたgotoステヌトメントであり、コヌルスタックをコヌルグラフに倉換したす。最も深刻な非孊術プロゞェクトがその䜿甚を犁止たたは制限するのには十分な理由がありたす。 ステヌトフルオブゞェクトは、制埡を任意にスタックに転送しおから呜什の実行を再開するメ゜ッドを呌び出したす...それは悪い考えのように聞こえたす。

@KamyarM本質的にはそうですが、実際にはそうではありたせん。 私の意芋では、ここでは明瀺的であり、Goのむディオムを砎っおいないためです。

どうしお

  1. withステヌトメント内の匏は、新しい倉数を宣蚀できないため、ブロック倉数から評䟡するこずを明瀺的に瀺しおいたす。
  2. with内のステヌトメントは、 tryおよびcatchブロック内のように動䜜したす。 実際、最悪のシナリオでwithの状態を評䟡する必芁がある次の各呜什では、速床が䜎䞋したす。
  3. 蚭蚈䞊、ハンドラヌは垞にロヌカルになるため、過剰なifを削陀し、䟋倖ハンドラヌを䜜成しないようにしたす withの匏ずelseブロック。
  4. throwため、スタックを巻き戻す必芁はありたせん

ps。 私が間違っおいる堎合は私を蚂正しおください。

@ardhitama
KamyarMは、 withステヌトメントがtry catchず同じくらい醜く芋え、通垞のコヌドフロヌにむンデントレベルを導入するずいう意味で正しいです。
各゚ラヌを個別に修正するずいう元の提案のアむデアに぀いおも蚀及しおいたせん。 䞀緒にグルヌプ文ずいうそれだけのtryでキャッチ、たたは他の方法で゚レガントに仕事に行くのではありたせん。

@gladkikhartem
はい、したがっお、私は代わりに「鉄道指向プログラミング」を採甚するこずを提案し、明瀺性を削陀しないようにしたす。 問題を攻撃するのは別の角床です。他の゜リュヌションでは、コンパむラヌにif err != nilを自動的に曞き蟌たせないこずで問題を解決したいず考えおいたす。

withは、゚ラヌ凊理だけでなく、他の制埡フロヌにも圹立ちたす。

@gladkikhartem
Try Catch Finallyブロックは矎しいず思いたす。 If err!=nil ...は実際には醜いコヌドです。

Goは単なるプログラミング蚀語です。 他にもたくさんの蚀語がありたす。 私は、囲碁コミュニティの倚くがそれを自分たちの宗教のように芋おおり、間違いを倉えたり認めたりするこずを受け入れおいないこずを知りたした。 これは間違っおいたす。

@gladkikhartem

Goの䜜者がそれをGo ++たたはGoたたはGoJavaず呌んで、そこにTry Catch Finallyを玹介しおも倧䞈倫です;

@KamyarM

䞍必芁な倉曎を回避するこずは、゚ンゞニアリングの取り組みにずっお必芁であり、重芁です。 人々がこの文脈で倉化を蚀うずき、圌らは実際には_より良い方向ぞの倉化_を意味し、それはその意図された結論ぞの前提を導く_議論_で効果的に䌝えたす。

_ただあなたの心を開いおください_魅力は説埗力がありたせん。 皮肉なこずに、それはほずんどのプログラマヌが叀くお䞍栌奜だず芋なしおいるこずを_新しく改善された_ず蚀おうずしたす。

Goコミュニティが以前の過ちに぀いお話し合う倚くの提案や議論もありたす。 しかし、Goは単なるプログラミング蚀語であるずあなたが蚀うずき、私はあなたに同意したす。 それは囲碁のりェブサむトや他の堎所でそう蚀っおいたす、そしお私はそれを確認した䜕人かの人々にも話したした。

私は、囲碁コミュニティの倚くがそれを自分たちの宗教のように芋おおり、間違いを倉えたり認めたりするこずを受け入れおいないこずを知りたした。

Goは孊術研究に基づいおいたす。 個人的な意芋は関係ありたせん。

MicrosoftのCコンパむラの䞻芁な開発者でさえ、_exceptions_ぱラヌを管理するための悪い方法であるず公に認めおいたすが、Go / Rustモデルをより良い代替手段ずしお賞賛しおいたす http 

確かに、Goの゚ラヌモデルを改善する䜙地はありたすが、いく぀かの疑わしい利点ず匕き換えに非垞に耇雑になるだけなので、䟋倖のような゜リュヌションを採甚するこずはできたせん。

@ Dr-ひどい蚘事をありがずう。

しかし、GoLangをアカデミック蚀語ずしお蚀及しおいるずころはどこにも芋぀かりたせんでした。

ずころで、私のポむントを明確にするために、この䟋では

func Execute() error {
    err := Operation1()
    if err!=nil{
        return err
    }

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

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

    err = Operation4()
    return err
}

次のようにCで䟋倖凊理を実装するのず䌌おいたす。

         public void Execute()
        {

            try
            {
                Operation1();
            }
            catch (Exception)
            {
                throw;
            }
            try
            {
                Operation2();
            }
            catch (Exception)
            {
                throw;
            }
            try
            {
                Operation3();
            }
            catch (Exception)
            {
                throw;
            }
            try
            {
                Operation4();
            }
            catch (Exception)
            {
                throw;
            }
        }

それはCでの䟋倖凊理のひどい方法ではありたせんか 私の答えはむ゚スです、私はあなたのこずを知りたせん Goでは他に遞択肢はありたせん。 それはそのひどい遞択たたは高速道路です。 これがGOの状況であり、私には遞択の䜙地がありたせん。

ちなみに、あなたが共有した蚘事でも述べたように、どの蚀語でも远加の構文を必芁ずせずにGoのような゚ラヌ凊理を実装できるため、Goは実際には革新的な゚ラヌ凊理方法を実装しおいたせん。 ゚ラヌ凊理の方法がないため、゚ラヌ凊理にIfステヌトメントを䜿甚するように制限されおいたす。

ずころで、GOには掚奚されおいないPanic, Recover , Deferがあり、これはTry Catch Finallyに䌌おいたすが、私の個人的な意芋では、 Try Catch Finally構文は、䟋倖凊理のよりクリヌンで敎理された方法です。

@ Dr-ひどい

たた、これをチェックしおください
https://github.com/manucorporat/try

@KamyarM 、圌はGoが孊術蚀語であるずは蚀いたせんでした、圌はそれが孊術研究に基づいおいるず蚀いたした。 Goに関する蚘事もありたせんでしたが、Goが採甚した゚ラヌ凊理パラダむムを調査しおいたす。

manucorporat/tryが適切であるこずがわかった堎合は、コヌドで䜿甚しおください。 ただし、蚀語自䜓にtry/catchを远加するコストパフォヌマンス、蚀語の耇雑さなどは、トレヌドオフの䟡倀がありたせん。

@KamyarM
あなたの䟋は正確ではありたせん。 の代替

    err := Operation1()
    if err!=nil {
        return err
    }
    err = Operation2()
    if err!=nil{
        return err
    }
    err = Operation3()
    if err!=nil{
        return err
    }
    return Operation4()

になりたす

            Operation1();
            Operation2();
            Operation3();
            Operation4();

この䟋では、䟋倖凊理の方がはるかに優れおいるようです。 理論的には良いはずですが、実際には
゚ンドポむントで発生した゚ラヌごずに、正確な゚ラヌメッセヌゞを返信する必芁がありたす。
Goのアプリケヌション党䜓は通垞50の゚ラヌ凊理です。

         err := Operation1()
    if err!=nil {
        log.Print("input error", err)
                fmt.Fprintf(w,"invalid input")
        w.WriteHeader(http.StatusBadRequest)
        return
    }
    err = Operation2()
    if err!=nil{
        log.Print("controller error", err)
                fmt.Fprintf(w,"operation has no meaning in this context")
        w.WriteHeader(http.StatusBadRequest)
        return
    }
    err = Operation3()
    if err!=nil{
        log.Print("database error", err)
                fmt.Fprintf(w,"unable to access database, try again later")
        w.WriteHeader(http.StatusServiceUnavailable)
        return
    }

そしお、もし人々がキャッチを詊みるような匷力なツヌルを持っおいるなら、私は圌らが泚意深い゚ラヌ凊理を支持しおそれを䜿いすぎるず100確信しおいたす。

アカデミアが蚀及されおいるのは興味深いですが、囲碁は実際の経隓から孊んだ教蚓の集たりです。 誀った゚ラヌメッセヌゞを返す䞍正なAPIを䜜成するこずが目暙である堎合は、䟋倖凊理が最適です。

ただし、リク゚ストに䞍正な圢匏のJSON request bodyが含たれおいる堎合、 invalid HTTP header゚ラヌは発生したせん。䟋倖凊理は、䜿甚するC ++およびCAPIでそれを実珟する魔法の発射ず忘れのボタンです。圌ら。

APIカバレッゞが倧きい堎合、意味のある゚ラヌ凊理を実珟するのに十分な゚ラヌコンテキストを提䟛するこずは䞍可胜です。 これは、優れたアプリケヌションはGoで50の゚ラヌ凊理であり、゚ラヌを凊理するために非ロヌカル制埡転送を必芁ずする蚀語では90である必芁があるためです。

@gladkikhartem

あなたが蚀及した別の方法は、Cでコヌドを曞く正しい方法です。 これはわずか4行のコヌドであり、正垞な実行パスを瀺しおいたす。 それらのif err!=nilノむズはありたせん。 䟋倖が発生した堎合、それらの䟋倖を凊理する関数はTry Catch Finallyを䜿甚しおそれを凊理できたす同じ関数自䜓、たたは呌び出し元の呌び出し元たたは呌び出し元、たたは呌び出し元の呌び出し元の呌び出し元の呌び出し元である可胜性がありたす ...たたは、アプリケヌションで未凊理のすべおの゚ラヌを凊理するむベントハンドラヌ。プログラマヌにはさたざたな遞択肢がありたす。

err := Operation1()
    if err!=nil {
        log.Print("input error", err)
                fmt.Fprintf(w,"invalid input")
        w.WriteHeader(http.StatusBadRequest)
        return
    }
    err = Operation2()
    if err!=nil{
        log.Print("controller error", err)
                fmt.Fprintf(w,"operation has no meaning in this context")
        w.WriteHeader(http.StatusBadRequest)
        return
    }
    err = Operation3()
    if err!=nil{
        log.Print("database error", err)
                fmt.Fprintf(w,"unable to access database, try again later")
        w.WriteHeader(http.StatusServiceUnavailable)
        return
    }

シンプルに芋えたすが、それはトリッキヌなものです。 おそらく、システム゚ラヌ、ナヌザヌ゚ラヌ最善の意図を持っおいない可胜性のあるナヌザヌに内郚状態をリヌクするこずなく、およびHTTPコヌドを含むカスタム゚ラヌタむプをたずめるこずができたす。

func Chdir(dir string) error {
    if e := syscall.Chdir(dir); e != nil {
        return &PathError{"chdir", dir, e}
    }
    return nil
}

しかし、それを詊しおみおください

func Chdir(dir string) error {
    return  syscall.Chdir(dir) ? &PathError{"chdir", dir, err}:nil;
}
func Chdir(dir string) error {
    return  syscall.Chdir(dir) ? &PathError{"chdir", dir, err};
}



md5-9bcd2745464e8d9597cba6d80c3dcf40



```go
func Chdir(dir string) error {
    n , _ := syscall.Chdir(dir):
               // something to do
               fmt.Println(n)
}

それらのすべおには、読者にずっお物事を単玔化しない、ある皮の明癜でない魔法が含たれおいたす。 前の2぀の䟋では、 errは、ある皮の疑䌌キヌワヌドたたは自発的に発生する倉数になりたす。 埌者の2぀の䟋では、 :挔算子が䜕をしおいるのかがたったくわかりたせん。゚ラヌは自動的に返されたすか オペレヌタヌのRHSは単䞀のステヌトメントですか、それずもブロックですか

FWIW、 return newPathErr("chdir", dir, syscall.Chdir(dir))を実行できるようにラッパヌ関数を蚘述し、3番目のパラメヌタヌがnilの堎合は自動的にnil゚ラヌを返したす。 :-)

IMO、私が芋た䞭で最高の提案は21732に「簡玠化゚ラヌゎヌでの取り扱い」ず「远加のコンテキスト情報ず゚ラヌを返す」@mrkaspaからあるの目暙を達成するには

a, b, err? := f1()

これに拡匵したす

if err != nil {
   return nil, errors.Wrap(err, "failed")
}

そしお私はこれでそれをパニックにさせるこずができたす

a, b, err! := f1()

これに拡匵したす

if err != nil {
   panic(errors.Wrap(err, "failed"))
}

これにより、䞋䜍互換性が維持され、goでの゚ラヌ凊理のすべおの問題点が修正されたす。

これは、れロ以倖の倀や゚ラヌを返すbufio関数のようなケヌスには察応しおいたせんが、他の戻り倀が気になる堎合は、明瀺的な゚ラヌ凊理を行っおも問題ないず思いたす。 そしおもちろん、゚ラヌ以倖の戻り倀は、そのタむプに適切なnil倀である必芁がありたす。

 修食子は、関数ずのボむラヌプレヌト゚ラヌの受け枡しを枛らしたす。 修食子は、assertが䞀郚のメむン関数などの他の蚀語で䜿甚される堎所でも同じこずを行いたす。

この゜リュヌションには、非垞にシンプルで、やりすぎないずいう利点がありたすが、この提案曞に蚘茉されおいる芁件を満たしおいるず思いたす。

あなたが持っおいる堎合...

func foo() (int, int, error) {
    a, b, err? := f1()
    return a, b, nil
}
func bar() (int, error) {
    a, b, err? := foo()
    return a+b, nil
}

fooで問題が発生した堎合、 barの呌び出しサむトで、゚ラヌは意味を远加せずに同じテキストで二重にラップされたす。 少なくずも、私は提案のerrors.Wrap郚分に反察したす。

しかし、さらに拡倧するず、これの期埅される結果は䜕ですか

func baz() (a, b int, err error) {
  a = 1
  b = 2
  a, b, err? = f1()
  return

aずbはnil倀に再割り圓おされたすか もしそうなら、それは魔法であり、避けるべきだず私は感じおいたす。 圌らは以前に割り圓おられた倀を実行したすか 私は名前付きの戻り倀を自分で気にしたせんが、それでもこの提案の目的のために考慮する必芁がありたす。

@ dup2Xええ、蚀語を削陀したしょう、それはもっずそうあるべきです

@ object88゚ラヌが発生した堎合、他のすべおが

ラッピングに関しおは、デフォルトのメッセヌゞは䜕も圹に立たないず思いたす。 ゚ラヌを連鎖させるだけでも問題ありたせん。 䟋倖に内郚䟋倖がある堎合のように。 ラむブラリの奥深くで゚ラヌをデバッグするのに非垞に䟿利です。

敬意を衚しお、私は同意したせん、@ creker。 このシナリオの䟋は、nil以倖の゚ラヌの堎合でも、nil以倖の戻り倀のGo stdlibにあり、実際には、 bufio.Reader構造䜓のいく぀かの関数のように機胜したす。 私たちGoプログラマヌは、すべおの゚ラヌをチェック/凊理するこずを積極的に奚励されおいたす。 nil以倖の戻り倀ず゚ラヌを取埗するよりも、゚ラヌを無芖する方がひどい感じがしたす。 匕甚する堎合、nilsを返し、゚ラヌをチェックしないず、無効な倀を操䜜しおいる可胜性がありたす。

しかし、それはさおおき、これをもう少し調べおみたしょう。 ?挔算子のセマンティクスは䜕でしょうか errorむンタヌフェヌスを実装する型にのみ適甚できたすか 他のタむプに適甚したり、匕数を返したりできたすか ゚ラヌを実装しない型に適甚できる堎合、nil以倖の倀/ポむンタヌによっおトリガヌされたすか ?挔算子を耇数の戻り倀に適甚できたすか、それずもコンパむラ゚ラヌですか

@erwbgy
有甚なものを添付せずに゚ラヌを返したい堎合は、コンパむラにすべおの未凊理の゚ラヌを「if err= nilreturn ...」ずしお凊理するように指瀺する方がはるかに簡単です。次に䟋を瀺したす。

func doStuff() error {
    doAnotherStuff() // returns error
}

func doStuff() error {
    res := doAnotherStuff() // returns string, error
}

そしお、远加の狂気の必芁はありたせんか この堎合の蚘号。

@ object88
ここに瀺されおいる゚ラヌラッピングの提案のほずんどを実際のコヌドに適甚しようずしたしたが、1぀の倧きな問題に盎面したした。コヌドが密集しすぎお、刀読できなくなりたす。
コヌドの高さを優先しお、コヌドの幅を犠牲にするだけです。
err= nilの堎合、゚ラヌを通垞でラッピングするず、実際には読みやすくするためにコヌドを拡散できるため、゚ラヌラッピングのために䜕も倉曎する必芁はないず思いたす。

@ object88

サむトを䜜成する堎合、nilsを返し、゚ラヌをチェックしないず、無効な倀で操䜜しおいる可胜性がありたす。

しかし、それは、nilのパニックのような明癜で芋぀けやすい゚ラヌを生成したす。 ゚ラヌ時に意味のある倀を返す必芁がある堎合は、明瀺的にそれを行い、その堎合に䜿甚できる倀を正確に文曞化する必芁がありたす。 ゚ラヌ時にたたたた倉数に含たれおいたランダムなものを返すだけでは危険であり、埮劙な゚ラヌに぀ながりたす。 繰り返したすが、それからは䜕も埗られたせん。

@gladkikhartem if err= nilの問題は、実際のロゞックが完党に倱われるこずです。コヌドが成功したパスで䜕をするのかを理解し、゚ラヌ凊理を気にしない堎合は、積極的に怜玢する必芁がありたす。 。 実際のコヌドが数行あり、それ以倖はすべお゚ラヌチェックであるCコヌドをたくさん読んでいるようなものになりたす。 人々は、そのすべおをラップしお関数の最埌に移動するマクロに頌るこずさえありたす。

適切に蚘述されたコヌドでロゞックがどのように密集しすぎるのかわかりたせん。 それは論理です。 コヌドのすべおの行には、気になる実際のコヌドが含たれおいたす。 あなたが望たないのは、ボむラヌプレヌトの線ず線を通過するこずです。 コメントを䜿甚し、それが圹立぀堎合はコヌドをブロックに分割したす。 しかし、それは蚀語ではなく実際のコヌドの問題のように聞こえたす。

再フォヌマットしない堎合、これは遊び堎で機胜したす。

a, b, err := Frob("one string"); if err != nil { return a, b, fmt.Errorf("couldn't frob: %v", err) }
// continue doing stuff with a and b

したがっお、元の提案、および䞊蚘の他の倚くの提案は、これらの100文字の明確な省略構文を考え出し、gofmtが改行の远加ず3行にわたるブロックの再フォヌマットを䞻匵するのを止めようずしおいるようです。

それで、gofmtを倉曎しお、耇数行のブロックを䞻匵するのをやめ、䞊の行から始めお、それをより短く、より明確にする方法を考え出すこずを想像しおみたしょう。

セミコロンの前の郚分割り圓おを倉曎しお、69文字を削枛する必芁はないず思いたす。 これらのうち、49はreturnステヌトメント、返される倀、および゚ラヌラッピングであり、その構文を倉曎するこずにはあたり䟡倀がありたせんたずえば、returnステヌトメントをオプションにするこずで、ナヌザヌを混乱させたす。

そのため、アンダヌスコアがコヌドのチャンクを衚す; if err != nil { _ }省略圢を芋぀けるこずができたす。 nilの比范が倚少芋えなくなったずしおも、わかりやすくするために、省略圢には明瀺的にerrを含める必芁があるず思いたす。そのため、 ; if _ != nil { _ }省略圢を考え出す必芁がありたす。

少しの間、1぀の文字を䜿甚するこずを想像しおみおください。 そのキャラクタヌが䜕であれ、プレヌスホルダヌずしお§を遞択したす。 その堎合、コヌドの行は次のようになりたす。

a, b, err := Frob("one string") § err return a, b, fmt.Errorf("couldn't frob: %v", err)

既存の代入構文や戻り構文を倉曎したり、目に芋えない魔法を発生させたりせずに、それよりもはるかに優れた方法がわかりたせん。 errずnilを比范しおいるずいう事実がすぐにはわからないずいう点で、ただいく぀かの魔法がありたす。

これは88文字で、100文字の行に合蚈12文字を節玄できたす。

だから私の質問はそれは本圓にやりがいがあるのか​​

線集私のポむントは、人々がGoのif err != nilブロックを芋お、「そのがらくたを取り陀くこずができればいいのに」ず蚀うずき、圌らが話しおいるこずの80〜90はあなたが本質的に持っおいるものだず思いたす゚ラヌを凊理するために行うこず_。 Goの構文によっお匕き起こされる実際のオヌバヌヘッドは最小限です。

@lpar 、あなたは私が䞊で適甚したのずほずんど同じ論理に埓っおいるので、圓然私はあなたの掚論に同意したす。 しかし、私はあなたがすべおの゚ラヌを右に眮くこずの芖芚的な魅力を軜芖しおいるず思いたす

a, b := Frob("one string")  § err { return ... }

単なる文字数の削枛を超える芁因で読みやすくなりたす。

@lparほずんど圹に立たないfmt.Errorfを削陀し、returnを特別な構文に倉曎し、呌び出しスタックを゚ラヌに導入しお、実際のコンテキストを持ち、単なる栄光の文字列ではない堎合は、さらに倚くの文字を節玄できたす。 それはあなたにこのようなものを残すでしょう

a, b, err? := Frob("one string")

私にずっおのGo゚ラヌの問題は、垞にコンテキストの欠劂でした。 文字列を返したり折り返したりするこずは、゚ラヌが実際に発生した堎所を特定するのにたったく圹立ちたせん。 そのため、たずえばgithub.com/pkg/errorsは私にずっお必須になりたした。 このような゚ラヌでは、Go゚ラヌ凊理の単玔さの利点ず、コンテキストを完党にキャプチャしお障害の正確な堎所を芋぀けるこずができる䟋倖の利点が埗られたす。

たた、䟋をそのたた䜿甚しおも、゚ラヌ凊理が右偎にあるずいう事実は、読みやすさを倧幅に向䞊させたす。 コヌドの実際の意味を理解するために、ボむラヌプレヌトの数行をスキップする必芁がなくなりたした。 ゚ラヌ凊理の重芁性に぀いおあなたが望むこずを蚀うこずができたすが、それを理解するためにコヌドを読むずき、私ぱラヌを気にしたせん。 私に必芁なのは成功した道です。 そしお、私が゚ラヌを必芁ずするずき、私はそれらを具䜓的に探したす。 ゚ラヌは、その性質䞊、䟋倖的なケヌスであり、可胜な限りスペヌスをずらないようにする必芁がありたす。

fmt.Errorfがerrors.Wrapず比范しお「圹に立たない」かどうかずいう問題は、どちらもほが同じように冗長であるため、この問題ず盎亀しおいるず思いたす。 実際のアプリケヌションでは、どちらも䜿甚しおいたせん。゚ラヌず゚ラヌが発生したコヌド行をログに蚘録する他の䜕かを䜿甚しおいたす。

ですから、゚ラヌ凊理が右偎にあるこずを本圓に気に入っおいる人もいるず思いたす。 PerlずRubyのバックグラりンドから来たずしおも、私はそれほど確信しおいたせん。

@lparコヌルスタックを自動的にキャプチャするため、 errors.Wrapを䜿甚したす。これらすべおの゚ラヌメッセヌゞは実際には必芁ありたせん。 私はそれが起こった堎所ず、おそらく、゚ラヌを生成した関数にどの匕数が枡されたかをもっず気にしたす。 あなたはあなたが同じようなこずをしおいるずさえ蚀っおいたす-あなたの゚ラヌメッセヌゞにいく぀かの文脈を提䟛するためにコヌドの行を蚘録しおください。 ゚ラヌにコンテキストを䞎えながらボむラヌプレヌトを枛らす方法を考えるこずができるずするずこれはほずんどここでの提案です。

゚ラヌは右偎にありたす。 私にずっお、それは単に堎所に぀いおではなく、゚ラヌ凊理が散らばっおいるコヌドを読むために必芁な認知的負荷を枛らすこずに぀いおです。 ゚ラヌが非垞に重芁であるため、゚ラヌず同じくらい倚くのスペヌスを䜿甚しおほしいずいう議論は買いたせん。 私は実際に圌らができるだけ離れるこずを望んでいたす。 それらはメむンストヌリヌではありたせん。

@creker

これは、ナヌザヌ入力の誀りが原因で゚ラヌを生成する本番システムの゚ラヌよりも、些现な開発者゚ラヌを説明しおいる可胜性が高くなりたす。 ゚ラヌを特定するために必芁なのが行番号ずファむルパスだけである堎合は、コヌドを蚘述しただけで、䜕が問題なのかをすでに知っおいる可胜性がありたす。

@䟋倖に䌌おいるため。 ほずんどの堎合、コヌルスタックず䟋倖メッセヌゞで堎所を特定し、゚ラヌが発生した堎所を特定できたす。 より耇雑なケヌスでは、少なくずも゚ラヌが発生した堎所を知っおいたす。 䟋倖は、デフォルトでこの利点を提䟛したす。 Goを䜿甚するず、基本的にコヌルスタックを゚ミュレヌトしお゚ラヌを連鎖させるか、実際のコヌルスタックを含める必芁がありたす。

適切に蚘述されたコヌドでは、゚ラヌが予想されるため、ほずんどの堎合、行番号ずファむルパスから正確な原因がわかりたす。 あなたは実際にそれが起こるかもしれない準備のためにいく぀かのコヌドを曞きたした。 予期しないこずが起こった堎合は、そうです。コヌルスタックは原因を特定したせんが、怜玢スペヌスを倧幅に削枛したす。

@なので

私の経隓では、ナヌザヌ入力゚ラヌはほが即座に凊理されたす。 実際に問題ずなる本番゚ラヌはコヌドの奥深くで発生したずえば、サヌビスがダりンしお別のサヌビスが゚ラヌをスロヌする、適切なスタックトレヌスを取埗するのに非垞に圹立ちたす。 䟡倀のあるこずずしお、Javaスタックトレヌスは、メッセヌゞではなく、本番環境の問題をデバッグするずきに非垞に圹立ちたす。

@creker
゚ラヌは単なる倀であり、関数の入力ず出力の䞀郚です。 圌らは「予期せぬ」こずはできたせんでした。
関数が゚ラヌを出した理由を知りたい堎合は、テスト、ロギングなどを䜿甚しおください...

@gladkikhartem珟実の䞖界では、それほど単玔ではありたせん。 はい、関数シグネチャに戻り倀ずしお゚ラヌが含たれおいるずいう意味で゚ラヌが発生するこずが予想されたす。 しかし、私が期埅するこずは、それが起こった理由ずそれを匕き起こした原因を正確に知っおいるこずです。したがっお、実際には、それを修正するか、たったく修正しないかを知っおいたす。 悪いナヌザヌ入力は通垞、゚ラヌメッセヌゞを芋るだけで簡単に修正できたす。 プロトコルバッファを䜿甚しおいお、䞀郚の必須フィヌルドが蚭定されおいない堎合、ネットワヌク䞊で受信するすべおのものを適切に怜蚌すれば、それは予想され、修正するのは非垞に簡単です。

この時点で、私はもはや私たちが議論しおいるこずを理解しおいたせん。 適切に実装された堎合、スタックトレヌスたたぱラヌメッセヌゞのチェヌンは非垞に䌌おいたす。 これらは怜玢スペヌスを削枛し、゚ラヌを再珟しお修正するための有甚なコンテキストを提䟛したす。 必芁なのは、十分なコンテキストを提䟛しながら゚ラヌ凊理を単玔化する方法を考えるこずです。 私は決しお、適切な文脈よりも単玔さが重芁であるず䞻匵しおいるわけではありたせん。

これがJavaの議論です—すべおの゚ラヌコヌドを別の堎所に移動しお、それを芋る必芁がないようにしたす。 私はそれが誀った方向に進んでいるず思いたす。 これを行うためのJavaのメカニズムが倧幅に倱敗しただけでなく、コヌドを芋るずき、゚ラヌが発生したずきのJavaの動䜜は、すべおが機胜したずきの動䜜ず同じくらい重芁です。

誰もその議論をしおいたせん。 ここで説明しおいるこずを、すべおの゚ラヌ凊理が1か所にある䟋倖凊理ず混同しないようにしたしょう。 それを「倧倱敗」ず呌ぶのは単なる意芋ですが、いずれにしおも囲碁がそれに戻るこずはないず思いたす。 Go゚ラヌ凊理はたったく異なり、改善するこずができたす。

@creker私は同じこずを指摘し、意味のある/有甚な゚ラヌメッセヌゞず芋なされるものを明確にするように䟝頌したした。

真実は、コヌルスタックず関数の匕数ず匕き換えに、可倉品質の゚ラヌメッセヌゞテキスト開発者がその瞬間にその知識でそれを曞くずいうバむアスがありたすをい぀でも提䟛するこずです。 ゚ラヌメッセヌゞテキスト fmt.Errorfたたはerrors.New を䜿甚するず、コヌルスタック/バックトレヌスを読み取りながら、゜ヌスコヌド内のテキストを怜玢するこずになりたすこれは䞀芋嫌われおいるようで、矎的理由からではないこずを願っおいたすファむル/行番号 errors.Wrapなどで盎接怜玢するこずに察応したす。

2぀の異なるスタむルですが、目的は同じです。これらの条件で実行時に䜕が起こったかを頭の䞭で再珟しようずするこずです。

このトピックに関しお、問題19991は、意味のある゚ラヌを定矩する2番目のスタむルぞのアプロヌチの有効な芁玄を䜜成しおいる可胜性がありたす。

すべおの゚ラヌコヌドを別の堎所に移動しお、それを芋る必芁がないようにしたす

@lpar 、゚ラヌ凊理を右に移動するこずに぀いおの私のポむントに応答しおいる堎合脚泚/文末脚泚Javaず脚泚私の提案には倧きな違いがありたす。 サむドノヌトは、コンテキストを倱うこずなく、わずかなアむシフトのみを必芁ずしたす。

@ gdm85

゜ヌスコヌド内のテキストを怜玢するこずになりたす

スタックトレヌスず連鎖゚ラヌメッセヌゞが類䌌しおいるずいう意味ずたったく同じです。 どちらも、゚ラヌが発生するたでのパスを蚘録したす。 メッセヌゞの堎合にのみ、メッセヌゞを曞くのに十分泚意しないず、プログラムのどこからでも送信される可胜性のある完党に圹に立たないメッセヌゞになっおしたう可胜性がありたす。 連鎖゚ラヌの唯䞀の利点は、倉数の倀を蚘録できるこずです。 そしお、それでさえ、関数の匕数や䞀般的な倉数の堎合には自動化でき、少なくずも私にずっおは、゚ラヌから必芁なほずんどすべおをカバヌしたす。 それらはただ倀であり、必芁に応じお「switch」ず入力するこずができたす。 しかし、ある時点でそれらをログに蚘録する可胜性があり、スタックトレヌスを衚瀺できるこずは非垞に䟿利です。

Goがパニックで䜕をするかを芋おください。 すべおのゎルヌチンの完党なスタックトレヌスを取埗したす。 ゚ラヌの原因を突き止めおすぐに修正するのに䜕回圹立ったか思い出せたせん。 それがいかに簡単であるか、私はしばしば驚かされたした。 それは完党に流れ、蚀語党䜓が非垞に予枬可胜であり、デバッガヌさえ必芁ありたせん。

Javaに関連するすべおのものには汚名があるようで、人々はしばしば議論を持ちたせん。 それは悪いからです。 私はJavaのファンではありたせんが、そのような掚論は誰の助けにもなりたせん。

繰り返したすが、゚ラヌは開発者がバグを修正するためのものではありたせん。 これは、゚ラヌ凊理の利点の1぀です。 Javaの方法は、それが゚ラヌ凊理であり、そうではないこずを開発者に教えおきたした。 ゚ラヌは、アプリケヌション局ずそれを超えるフロヌ局に存圚する可胜性がありたす。 Goの゚ラヌは、システムが実行するリカバリ戊略を制埡するために日垞的に䜿甚されたす。コンパむル時ではなく、実行時に䜿甚されたす。

これは、蚀語がスタックを解きほぐし、゚ラヌが発生する前に行ったすべおのメモリを倱うこずによっお゚ラヌの結果ずしおフロヌ制埡を無効にする堎合、理解できない可胜性がありたす。 ゚ラヌは、Goの実行時に実際に圹立ちたす。 なぜ行番号のようなものを運ぶ必芁があるのか​​わかりたせん-実行䞭のコヌドはそれをほずんど気にしたせん。

@なので

繰り返したすが、゚ラヌは開発者がバグを修正するためのものではありたせん

それは完党にそしお完党に間違っおいたす。 ゚ラヌはたさにその理由によるものです。 それらはそれに限定されたせんが、それは䞻な甚途の1぀です。 ゚ラヌは、システムに問題があるこずを瀺しおいるため、䜕かを行う必芁がありたす。 予想される簡単な゚ラヌの堎合は、TCPタむムアりトなどの回埩を詊みるこずができたす。 より深刻な問題に぀いおは、ログにダンプし、埌で問題をデバッグしたす。

これは、゚ラヌ凊理の利点の1぀です。 Javaの方法は、それが゚ラヌ凊理であり、そうではないこずを開発者に教えおきたした。

Javaが䜕を教えおくれたかはわかりたせんが、同じ理由で䟋倖を䜿甚したす。実行時にシステムが実行するリカバリ戊略を制埡するためです。 Goは、゚ラヌ凊理に関しお特別なこずは䜕もありたせん。

これは、蚀語がスタックを解きほぐし、゚ラヌが発生する前に行ったすべおのメモリを倱うこずによっお゚ラヌの結果ずしおフロヌ制埡を無効にする堎合、理解できない可胜性がありたす

私のためではなく、誰かのためかもしれたせん。

゚ラヌは、Goの実行時に実際に圹立ちたす。 なぜ行番号のようなものを運ぶ必芁があるのか​​わかりたせん-実行䞭のコヌドはそれをほずんど気にしたせん。

コヌドのバグを修正するこずに関心がある堎合は、行番号がそれを行う方法です。 これに぀いお教えおくれたのはJavaではありたせん。Cにはたさにその理由で__LINE__ず__FUNCTION__たす。 ゚ラヌをログに蚘録し、゚ラヌが発生した正確な堎所を蚘録する必芁がありたす。 そしお、䜕かがうたくいかないずき、あなたは少なくずも䜕かから始める必芁がありたす。 回埩䞍胜な゚ラヌによっお匕き起こされたランダムな゚ラヌメッセヌゞではありたせん。 そのような情報が必芁ない堎合は、無芖しおください。 それはあなたを傷぀けたせん。 しかし、少なくずもそれはそこにあり、必芁なずきに䜿甚するこずができたす。

ここの人々が䌚話を䟋倖ず゚ラヌ倀にシフトし続ける理由がわかりたせん。 誰もその比范をしおいたせんでした。 議論された唯䞀のこずは、スタックトレヌスが非垞に有甚であり、倚くのコンテキスト情報を運ぶずいうこずです。 それが理解できない堎合は、トレヌスが存圚しない完党に異なる宇宙に䜏んでいる可胜性がありたす。

それは完党にそしお完党に間違っおいたす。

しかし、私が参照しおいる本番システムはただ実行䞭であり、フロヌ制埡に゚ラヌを䜿甚し、Goで蚘述され、゚ラヌの䌝播にスタックトレヌスを䜿甚する蚀語の䜎速な実装に取っお代わりたした。

それが理解できない堎合は、トレヌスが存圚しない完党に異なる宇宙に䜏んでいる可胜性がありたす。

゚ラヌタむプを返すすべおの関数のコヌルスタック情報を連鎖させるには、自分の裁量でそれを行いたす。 スタックトレヌスは䜎速であり、セキュリティ䞊の理由からおもちゃプロゞェクトの倖郚での䜿甚には適しおいたせん。 圌らを䞀流のGo垂民にしお、単に思慮のない゚ラヌ䌝播戊略を支揎するこずは技術的な反則です。

そのような情報が必芁ない堎合は、無芖しおください。 それはあなたを傷぀けたせん。

゜フトりェアの肥倧化は、サヌバヌがGoで曞き盎される理由です。 衚瀺されないものでも、パむプラむンのスルヌプットが䜎䞋する可胜性がありたす。

TCPタむムアりトずログダンプの凊理に関するやや無関係なレッスンではなく、この機胜を䜿甚するこずでメリットが埗られる実際の゜フトりェアの䟋をお勧めしたす。

スタックトレヌスは遅くなりたす

スタックトレヌスが゚ラヌパスで生成されるこずを考えるず、それらがどれほど遅いかは誰も気にしたせん。 ゜フトりェアの通垞の操䜜はすでに䞭断されおいたす。

セキュリティ䞊の理由から、おもちゃのプロゞェクト以倖での䜿甚には適しおいたせん

これたでのずころ、「セキュリティ䞊の理由」のために、たたはそのこずに぀いおは、単䞀の本番システムがスタックトレヌスをオフにするのを芋たこずがありたせん。 䞀方、゚ラヌを生成するためにコヌドがたどったパスをすばやく特定できるこずは非垞に䟿利です。 そしお、これは倧芏暡なプロゞェクト向けであり、倚くの異なるチヌムがコヌドベヌスで䜜業しおおり、システム党䜓の完党な知識を持っおいる人は誰もいたせん。

衚瀺されないものでも、パむプラむンのスルヌプットが䜎䞋する可胜性がありたす。

いいえ、実際にはそうではありたせん。 前に述べたように、スタックトレヌスぱラヌ時に生成されたす。 ゜フトりェアが垞にそれらに遭遇しない限り、スルヌプットは1ビット圱響を受けたせん。

スタックトレヌスが゚ラヌパスで生成されるこずを考えるず、それらがどれほど遅いかは誰も気にしたせん。 ゜フトりェアの通垞の操䜜はすでに䞭断されおいたす。

真実ではない。

  • 通垞の操䜜の䞀郚ずしお゚ラヌが発生する可胜性がありたす。
  • ゚ラヌを回埩しおプログラムを続行できるため、パフォヌマンスには問題がありたす。
  • 1぀のルヌチンの速床を萜ずすず、ハッピヌパスで動䜜しおいる他のルヌチンからリ゜ヌスが倱われたす。

@ object88は、実際の補品コヌドを想像しおください。 どのくらいの゚ラヌが発生するず予想したすか あたり思いたせん。 少なくずも適切に䜜成されたアプリケヌションでは。 ゎルヌチンがビゞヌルヌプにあり、反埩ごずに垞に゚ラヌをスロヌする堎合は、コヌドに問題がありたす。 しかし、そうだずしおも、Goアプリケヌションの倧郚分がIOバりンドであるこずを考えるず、それは深刻な問題ではありたせん。

@なので

しかし、私が参照しおいる本番システムはただ実行䞭であり、フロヌ制埡に゚ラヌを䜿甚し、Goで蚘述され、゚ラヌの䌝播にスタックトレヌスを䜿甚する蚀語の䜎速な実装に取っお代わりたした。

申し蚳ありたせんが、これは私が蚀ったこずずは䜕の関係もない無意味な文章です。 答える぀もりはありたせん。

スタックトレヌスは遅くなりたす

遅いですが、いくらですか それは重芁ですか そうは思いたせん。 Goアプリケヌションは䞀般にIOバりンドです。 この堎合、CPUサむクルを远いかけるのはばかげおいたす。 あなたはCPUを消費するGoランタむムではるかに倧きな問題を抱えおいたす。 バグの修正に圹立぀䟿利な機胜を捚おるのは議論の䜙地がありたせん。

セキュリティ䞊の理由から、おもちゃのプロゞェクト以倖での䜿甚には適しおいたせん。

存圚しない「セキュリティ䞊の理由」に぀いおは、わざわざ取り䞊げる぀もりはありたせん。 ただし、通垞、アプリケヌショントレヌスは内郚に保存されおおり、開発者のみがそれらにアクセスできるこずを思い出しおください。 そしお、関数名を非衚瀺にしようずするず、ずにかく時間の無駄になりたす。 それはセキュリティではありたせん。 それに぀いお詳しく説明する必芁がないこずを願っおいたす。

セキュリティ䞊の理由で䞻匵するなら、䟋えばmacOS / iOSに぀いお考えおほしい。 すべおのスレッドのスタックずすべおのCPUレゞスタの倀を含むパニックやクラッシュダンプをスロヌしおも問題ありたせん。 それらがこれらの「セキュリティ䞊の理由」の圱響を受けおいるのを芋ないでください。

圌らを䞀流のGo垂民にしお、単に思慮のない゚ラヌ䌝播戊略を支揎するこずは技術的な反則です。

これ以䞊䞻芳的になれたすか 「思いがけない゚ラヌ䌝播戊略」それはどこで芋たしたか

゜フトりェアの肥倧化は、サヌバヌがGoで曞き盎される理由です。 衚瀺されないものでも、パむプラむンのスルヌプットが䜎䞋する可胜性がありたす。

繰り返したすが、いくらですか

TCPタむムアりトずログダンプの凊理に関するやや無関係なレッスンではなく、この機胜を䜿甚するこずでメリットが埗られる実際の゜フトりェアの䟋をお勧めしたす。

この時点で、私はプログラマヌ以倖の誰かず話しおいるようです。 トレヌスは、すべおの゜フトりェアにメリットをもたらしたす。 これは、バグの修正に圹立぀すべおの蚀語およびすべおのタむプの゜フトりェアに共通の手法です。 詳现に぀いおは、りィキペディアをご芧ください。

コンセンサスなしに非垞に倚くの非生産的な議論があるずいうこずは、この問題を解決するための゚レガントな方法がないこずを意味したす。

@ object88
Goは他のゎルヌチンのブロックが解陀されるのを埅぀必芁があるため、すべおのゎルヌチンのトレヌスを取埗する堎合は、スタックトレヌスが遅くなる可胜性がありたす。
珟圚実行しおいるゎルヌチンをトレヌスするだけであれば、それほど遅くはありたせん。

@creker
トレヌスは、すべおの゜フトりェアに利益をもたらし、それはあなたがトレヌスしおいるかに䟝存したす。 ほずんどのGoプロゞェクトでは、䞊行性が関係しおいるため、スタックのトレヌスは良い考えではありたせんでした。 デヌタは前埌に移動し、倚くのものが盞互に通信しおおり、䞀郚のゎルヌチンはほんの数行のコヌドです。 このような堎合にスタックトレヌスがあるず圹に立ちたせん。
そのため、ログに曞き蟌たれたコンテキスト情報でラップされた゚ラヌを䜿甚しお、同じスタックトレヌスを再䜜成したすが、これは実際のゎルヌチンスタックではなく、アプリケヌションロゞック自䜓にバむンドされたす。
猫をやれるように* .log | grep "orderID = xxx"を実行し、゚ラヌの原因ずなった実際のアクションシヌケンスのスタックトレヌスを取埗したす。
Goの同時実行性により、コンテキストが豊富な゚ラヌはスタックトレヌスよりも䟡倀がありたす。

@gladkikhartemは、適切な議論を曞くために時間を割いお

私はあなたの議論を理解し、郚分的に同意したす。 それでも、少なくずも5぀の関数のスタックを凊理する必芁があるこずに気付きたした。 それは、䜕が起こっおいるのか、どこから探し始めるべきかを理解するのに十分な倧きさです。 しかし、非垞に小さなゎルヌチンスタックトレヌスが倚数ある非垞に同時のアプリケヌションでは、その利点が倱われたす。 私が同意するこず。

@creker

実際の補品コヌドを想像しおください。 どのくらいの゚ラヌが発生するず予想したすか [...]、Goアプリケヌションの倧郚分がIOバりンドであるこずを考えるず、それは深刻な問題ではありたせん。

IOバりンド操䜜に぀いお蚀及するのは良いこずです。 io.Reader Readメ゜ッドは、EOFで正垞な゚ラヌを返したす。 だから、それは幞せな道でたくさん起こるだろう。

@urandom

スタックトレヌスは、システムのプロファむリングに圹立぀情報を意図せずに公開したす。

  • ナヌザヌ名
  • ファむルシステムパス
  • バック゚ンドデヌタベヌスのタむプ/バヌゞョン
  • トランザクションフロヌ
  • オブゞェクト構造
  • 暗号化アルゎリズム

平均的なアプリケヌションが゚ラヌタむプでスタックフレヌムを収集するオヌバヌヘッドに気付くかどうかはわかりたせんが、パフォヌマンスが重芁なアプリケヌションでは、珟圚の関数呌び出しのオヌバヌヘッドのために、倚くの小さなGo関数が手動でむンラむン化されたす。 トレヌスするず悪化したす。

Goの目暙は、シンプルで高速な゜フトりェアを䜿甚するこずであり、トレヌスは䞀歩埌退するず思いたす。 小さな関数を蚘述し、それらの関数から゚ラヌを返すこずができるはずです。これにより、埓来ずは異なるタむプの゚ラヌや手動のむンラむン化が促進されたす。

@creker

私はあなたにさらなる䞍協和音を匕き起こす䟋を䞎えるこずを避けたす。 ご䞍䟿をおかけしお申し蚳ございたせん。

名前がすぐにその機胜を明らかにする新しいキヌワヌド「returnif」を䜿甚するこずを提案したす。 たた、゚ラヌ凊理よりも倚くのナヌスケヌスで䜿甚できるほど十分な柔軟性がありたす。

䟋1名前付きreturnを䜿甚

a、err = somethingb
err= nil {の堎合
戻る
}

になりたす

a、err = somethingb
returnif err= nil

䟋2名前付きリタヌンを䜿甚しない

a、err= somethingb
err= nil {の堎合
を返す、゚ラヌ
}

になりたす

a、err= somethingb
returnif err= nil {a、err}

名前付き返品の䟋に関しお、あなたはどういう意味ですか...

a, err = something(b)
returnif err != nil

@ambernardino
代わりにfmtツヌルを曎新するだけで、蚀語構文を曎新したり、新しい、圹に立たないキヌワヌドを远加したりする必芁がないのはなぜですか。

a, err := something(b)
if err != nil { return a, err }

たた

a, err := something(b)
    if err != nil { return a, err }

@gladkikhartemアむデアは、゚ラヌを䌝播するたびにそれを入力するこずではなく、私はむしろこれを望み、同じように機胜するはずです

a, err? := something(b)

@mrkaspa
アむデアは、コヌドをより読みやすくするこずです。 コヌドの入力は問題ではなく、読み取りは問題です。

@gladkikhartem rustはそのアプロヌチを䜿甚しおおり、読みにくくなるずは思わない

@gladkikhartem ?読みにくくなるずは思いたせん。 ノむズを完党に陀去しおいるず思いたす。 私にずっおの問題は、ノむズがあるず、有甚なコンテキストを提䟛する可胜性も排陀されるこずです。 通垞の゚ラヌメッセヌゞをプラグむンしたり、゚ラヌをラップしたりできる堎所がわかりたせん。 コヌルスタックは明らかな解決策ですが、すでに述べたように、すべおの人に圹立぀わけではありたせん。

@mrkaspa
そしお、それはそれを読みにくくするず思いたす、次は䜕ですか 私たちは最善の解決策を芋぀けようずしおいたすか、それずも単に意芋を共有しようずしおいたすか

@creker
「」 䜕が返されるのかはそれほど明確ではなく、もちろん人はこれが䜕をしおいるのかを知っおいる必芁があるため、キャラクタヌは読者に認知的負荷を加えたす。 そしおもちろん  サむンは読者の心に疑問を投げかけたす。

前に述べたように、err= nilコンパむラを削陀したい堎合は、未䜿甚の゚ラヌパラメヌタを怜出し、それらを自分で転送できたす。
ず

a, err? := doStuff(a,b)
err? := doAnotherStuff(b,z,d,g)
a, b, err? := doVeryComplexStuff(b)

読みやすくなりたす

a := doStuff(a,b)
doAnotherStuff(b,z,d,g)
a, b := doVeryComplexStuff(b)

同じ魔法で、タむプするものが少なく、考えるものが少ない

@gladkikhartemええず、読者が䜕か新しいこずを孊ぶ必芁のない解決策はないず思いたす。 それは蚀語を倉曎した結果です。 トレヌドオフを行う必芁がありたす。基本的な甚語で䜕が行われおいるのかを正確に瀺す顔の構文に冗長性を持たせるか、冗長性を隠したり、構文の糖衣を远加したりできる新しい構文を導入したす。他に方法はありたせん。 読者が孊ぶために䜕かを远加するものを単に拒吊するこずは逆効果です。 すべおのGo2の問題を閉じお、それを1日ず呌ぶ方がよいでしょう。

あなたの䟋のように、それはさらに倚くの魔法のものを導入し、開発者が゚ラヌにコンテキストを提䟛できるようにする構文を導入するためのむンゞェクションポむントを非衚瀺にしたす。 そしお、最も重芁なのは、どの関数呌び出しが゚ラヌをスロヌする可胜性があるかに関する情報を完党に隠すこずです。 それはたすたす䟋倖のようなにおいがしたす。 たた、゚ラヌを再スロヌするこずだけを真剣に考えおいる堎合は、スタックトレヌスが必須になりたす。これは、その堎合にコンテキストを保持できる唯䞀の方法だからです。

元の提案は、実際にはすでにすべおをかなりうたくカバヌしおいたす。 それは十分に冗長であり、゚ラヌをラップしお有甚なコンテキストを提䟛するのに適した堎所を提䟛したす。 しかし、䞻な問題の1぀は、この魔法の「゚ラヌ」です。 魔法ではなく、冗長でもないので、醜いず思いたす。 ちょっず真ん䞭です。 それをより良くするかもしれないのは、より倚くの魔法を導入するこずです。

||が、元の゚ラヌを自動的にラップする新しい゚ラヌを生成するずしたらどうでしょうか。 したがっお、䟋は次のようになりたす

func Chdir(dir string) error {
    syscall.Chdir(dir) || &PathError{"chdir", dir}
    return nil
}

errが消えお、すべおのラッピングが暗黙的に凊理されたす。 次に、これらの内郚゚ラヌにアクセスする方法が必芁です。 Inner() errorような別のメ゜ッドをerrorむンタヌフェヌスに远加しおも、うたくいかないず思いたす。 1぀の方法は、 unwrap(error) []errorような組み蟌み関数を導入するこずです。 それが行うこずは、それらがラップされた順序ですべおの内郚゚ラヌのスラむスを返すこずです。 そうすれば、内郚゚ラヌやそれらの範囲にアクセスできたす。

errorは単なるむンタヌフェむスであり、カスタムのerrorタむプのラップされた゚ラヌを配眮する堎所が必芁であるこずを考えるず、これの実装には疑問がありたす。

私にずっお、これはすべおのボックスにチェックマヌクを付けたすが、やや䞍思議すぎるかもしれたせん。 しかし、゚ラヌむンタヌフェむスは定矩䞊非垞に特殊であるため、䞀玚垂民に近づけるこずは悪い考えではないかもしれたせん。 ゚ラヌ凊理は、通垞のGoコヌドであり、特別なこずは䜕もないため、冗長です。 それは玙の䞊や掟手な芋出しを䜜るのに良いかもしれたせんが、゚ラヌはそのような扱いを正圓化するにはあたりにも特別です。 圌らは特別なケヌシングが必芁です。

゚ラヌチェックの数たたは個々のチェックの長さを枛らすこずに぀いおの圓初の提案はありたすか

埌者の堎合、条件文ず繰り返し文が1぀しかないずいう理由で、提案の必芁性に異議を唱えるのは簡単です。 ルヌプが嫌いな人もいたすが、暗黙のルヌプ構造も提䟛する必芁がありたすか

これたでに提案された構文の倉曎は、興味深い思考実隓ずしお圹立ちたしたが、元の構文の倉曎ほど明確、発音可胜、たたは単玔なものはありたせん。 Goはbashではなく、゚ラヌに぀いお「魔法」である必芁はありたせん。

私はたすたすこれらの提案を読み、議論が「䜕か新しいものを远加するので、それは悪い、読めない、すべおをそのたたにしおおく」に他ならない人々をたすたす芋おいたす。

@as提案は、それが達成しようずしおいるこずの芁玄を瀺しおいたす。 䜕が行われおいるのかはかなり明確に定矩されおいたす。

オリゞナルず同じくらい明確、発音可胜、たたはシンプル

どんな提案も新しい構文を導入し、䞀郚の人々にずっお新しいこずは「読めない、耇雑ななど」ず同じように聞こえたす。 それが新しいからずいっお、それがはっきりしおいたり​​、発音しやすく、単玔になったりするこずはありたせん。 "||" ず "" 䟋は、それが䜕をするかを知っおいれば、既存の構文ず同じくらい明確で単玔です。 それずも、「->」ず「<-」は魔法が倚すぎお、読者はそれらが䜕を意味するのかを知らなければならない、ず䞍平を蚀い始める必芁がありたすか それらをメ゜ッド呌び出しに眮き換えたしょう。

Goはbashではなく、゚ラヌに぀いお「魔法」である必芁はありたせん。

それは完党に根拠がなく、䜕の議論ずしおも数えられたせん。 Bashず関係があるのは、私を超えおいたす。

@creker
はい、私はむベントにもっず魔法を導入したあなたに完党に同意したす。 私の䟋はの続きです少ないものを入力するずいうオペレヌタヌの考え。

私たちは䜕かを犠牲にしお、いく぀かの倉化ずもちろんいく぀かの魔法を導入する必芁があるこずに同意したす。 それは、䜿いやすさの長所ずそのような魔法の短所のバランスにすぎたせん。

オリゞナル|| 提案はかなり玠晎らしく、実際にテストされおいたすが、私の意芋ではフォヌマットは醜いです、私はフォヌマットをに倉曎するこずをお勧めしたす

syscal.Chdir(dir)
    || return &PathError{"chdir", dir}

PSあなたはそのような魔法の構文の倉皮に぀いおどう思いたすか

syscal.Chdir(dir) {
    return &PathError{"chdir", dir}
}

@gladkikhartemはどちらも読みやすさの芳点からはかなり芋栄えがしたすが、埌者の方が悪い感じがしたす。 それは私がよくわからないこの奇劙なブロックスコヌプを玹介したす。

構文を単独で芋るのではなく、関数のコンテキストで芋るこずをお勧めしたす。 このメ゜ッドには、いく぀かの異なる゚ラヌ凊理ブロックがありたす。

func (l *Loader) processDirectory(p *Package) (*build.Package, error) {
        absPath, err := p.preparePath()
        if err != nil {
                return nil, err
        }
    fis, err := l.context.ReadDir(absPath)
    if err != nil {
        return nil, err
    } else if len(fis) == 0 {
        return nil, nil
    }

    buildPkg, err := l.context.Import(".", absPath, 0)
    if err != nil {
        if _, ok := err.(*build.NoGoError); ok {
            // There isn't any Go code here.
            return nil, nil
        }
        return nil, err
    }

    return buildPkg, nil
}

提案された倉曎は、この機胜をどのようにクリヌンアップしたすか

func (l *Loader) processDirectory(p *Package) (*build.Package, error) {
    absPath, err? := p.preparePath()
    fis, err? := l.context.ReadDir(absPath)
    if len(fis) == 0 {
        return nil, nil
    }

    buildPkg, err := l.context.Import(".", absPath, 0)
    if err != nil {
         if _, ok := err.(*build.NoGoError); ok {
             // There isn't any Go code here.
             return nil, nil
         }
         return nil, err
    }

    return buildPkg, nil
}

@bcmillsの提案の方が適しおいたす。

func (l *Loader) processDirectory(p *Package) (*build.Package, error) {
    absPath := p.preparePath()        =? err { return nil, err }
    fis := l.context.ReadDir(absPath) =? err { return nil, err }
    if len(fis) == 0 {
        return nil, nil
    }
    buildPkg := l.context.Import(".", absPath, 0) =? err {
        if _, ok := err.(*build.NoGoError); ok {
            // There isn't any Go code here.
            return nil, nil
        }
        return nil, err
    }
    return buildPkg, nil
}

@ object88

func (l *Loader) processDirectory(p *Package) (p *build.Package, err error) {
        absPath, err := p.preparePath() {
        return nil, fmt.Errorf("prepare path: %v", err)
    }
    fis, err := l.context.ReadDir(absPath) {
        return nil, fmt.Errorf("read dir: %v", err)
    }
    if len(fis) == 0 {
        return nil, nil
    }

    buildPkg, err := l.context.Import(".", absPath, 0) {
        err, ok := err.(*build.NoGoError)
                if !ok {
            return nil, fmt.Errorf("buildpkg: %v",err)
        }
        return nil, nil
    }
    return buildPkg, nil
}

これを突っ蟌み続けたす。 たぶん、より完党な䜿甚䟋を思い぀くこずができたす。

@erwbgy 、これは私には最高に芋えたすが、支払いがそれほど玠晎らしいずは確信しおいたせん。

  • ゚ラヌ以倖の戻り倀は䜕ですか それらは垞にれロ倀ですか 名前付きリタヌンに以前に割り圓おられた倀が_あった_堎合、それはオヌバヌラむドされたすか 名前付きの倀が゚ラヌ関数の結果を栌玍するために䜿甚される堎合、それは返されたすか
  • ?挔算子を゚ラヌ以倖の倀に適甚できたすか (!ok)?やok!?なこずをしおもいいですか割り圓おず操䜜をバンドルしおいるので少し奇劙です たたは、この構文はerrorのみ有効ですか

@rodcorsi 、これは私をReadDirなく、 ReadBuildTargetDirectoryForFileInfoか、そのようなばかげたものだった堎合はどうなるでしょうか。 たたは、おそらくあなたは倚数の議論を持っおいたす。 preparePathの゚ラヌ凊理も、画面からはみ出しおしたいたす。 氎平方向の画面サむズが制限されおいるデバむスたたはGithubのようにそれほど広くないビュヌポヌトでは、 =?郚分が倱われる可胜性がありたす。 垂盎スクロヌルは非垞に埗意です。 氎平ではそれほど倚くありたせん。

@gladkikhartem 、 errorむンタヌフェヌスを実装するいく぀かの最埌の匕数に関連付けられおいるようです。 それは関数宣蚀によく䌌おいたす、そしおそれはただ..._感じ_奇劙です。 okスタむルの戻り倀に関連付ける方法はありたすか 党䜓ずしお、1行しか賌入しおいたせん。

@ object88
ワヌドラップは、非垞に幅広いコヌドの問題を解決したす。 広く䜿われおいたせんか

非垞に長い関数呌び出しに関する@ object88 。 ここで䞻な問題に察凊したしょう。 問題は、画面から抌し出された゚ラヌ凊理ではありたせん。 問題は、長い関数名や匕数の倧きなリストです。 ゚ラヌ凊理が画面倖にあるこずに぀いお議論する前に、これを修正する必芁がありたす。

デフォルトでワヌドラップに蚭定されおいるIDEたたはコヌドフレンドリヌなテキスト゚ディタはただ芋たこずがありたせん。 そしお、ペヌゞがロヌドされた埌にCSSを手動でハッキングする以倖に、Githubを䜿甚しおそれを行う方法をたったく芋぀けおいたせん。

そしお、私はコヌド幅が重芁な芁玠であるず思いたす-それはこの提案の掚進力である_可読性_を物語っおいたす。 䞻匵は、゚ラヌの呚りに「コヌドが倚すぎる」ずいうこずです。 機胜がないずいうわけではなく、゚ラヌを他の方法で実装する必芁があるずいうわけではありたせんが、コヌドがうたく読み取れないずいうこずです。

@ object88
はい、このコヌドは、゚ラヌむンタヌフェむスを最埌のパラメヌタずしお返すすべおの関数で機胜したす。

行の節玄に関しおは、より少ない行数でより倚くの情報を入力するこずはできたせん。 コヌドは均等に分散し、密床が高すぎたり、すべおのステヌトメントの埌にスペヌスを入れたりしないようにする必芁がありたす。
私はそれが関数宣蚀のように芋えるこずに同意したすが、同時にそれは既存の堎合ず非垞に䌌おいたす...; err= nil {ステヌトメントなので、人々はあたり混乱したせん。

コヌド幅は重芁な芁玠です。 80行の゚ディタヌず80行のコヌドが関数呌び出しであり、その埌に||がある堎合はどうなりたすか 返したすか 関数が䜕かを返すこずを識別できたせん。これは、読み取るものが、戻り倀のない有効なgoコヌドになるためです。

完党を期すために、 ||構文、自動マゞック゚ラヌラッピング、および゚ラヌ以倖の戻り倀の自動れロ化を䜿甚した䟋を瀺したす。

func (l *Loader) processDirectory(p *Package) (*build.Package, error) {
        absPath := p.preparePath() || errors.New("prepare path")
    fis := l.context.ReadDir(absPath) || errors.New("ReadDir")
    if len(fis) == 0 {
        return nil, nil
    }

    buildPkg, err := l.context.Import(".", absPath, 0)
    if err != nil {
        if _, ok := err.(*build.NoGoError); ok {
            // There isn't any Go code here.
            return nil, nil
        }
        return nil, err
    }

    return buildPkg, nil
}

他の戻り倀に぀いおの質問に぀いお。 ゚ラヌが発生した堎合、すべおの堎合で倀はれロになりたす。 それが重芁だず思う理由に぀いおは、すでに説明したした。

問題は、あなたの䟋がそもそも関係しおいないずいうこずです。 しかし、それでも、少なくずも私にずっおは、この提案が䜕を衚しおいるのかを瀺しおいたす。 私が解決したいのは、最も䞀般的で乱暎に䜿甚されおいるむディオムです

err := func()
if err != nil {
    return err
}

この皮のコヌドは、䞀般に゚ラヌ凊理の倧きな郚分最倧ではないにしおもであるこずに同意できたす。 したがっお、その堎合を解決するこずは論理的です。 そしお、゚ラヌにもっず関係するこずをしたい堎合は、いく぀かのロゞックを適甚しおください-それを実行しおください。 ここで、プログラマヌが読んで理解するための実際のロゞックが冗長性である必芁がありたす。 私たちが必芁ずしないのは、無意識の定型文を読むためにスペヌスず時間を無駄にするこずです。 それは無意味ですが、それでもGoコヌドの重芁な郚分です。

暗黙的にれロ倀を返すこずに぀いおの以前の話に぀いお。 ゚ラヌ時に意味のある倀を返す必芁がある堎合は、それを遞択しおください。 ここでも、冗長性は優れおおり、コヌドを理解するのに圹立ちたす。 もっず耇雑なこずをする必芁がある堎合は、シンタックスシュガヌを捚おおも問題ありたせん。 たた、 ||は、䞡方のケヌスを解決するのに十分な柔軟性がありたす。 ゚ラヌ以倖の倀は省略でき、暗黙的にれロになりたす。 たたは、必芁に応じお明瀺的に指定するこずもできたす。 ゚ラヌを返し、他のすべおをれロにしたい堎合も含たれる、これに関する別の提案さえあるこずを芚えおいたす。

@ object88

䞻匵は、゚ラヌの呚りに「コヌドが倚すぎる」ずいうこずです。

それは単なるコヌドではありたせん。 䞻な問題は、゚ラヌの呚りに無意味な定型文が倚すぎお、゚ラヌ凊理の非垞に䞀般的なケヌスがあるこずです。 読む䟡倀のあるものがある堎合、冗長性は重芁です。 ゚ラヌを再スロヌするこずを陀いお、 if err == nil then return errは䜕の䟡倀もありたせん。 このようなプリミティブロゞックの堎合、倚くのスペヌスが必芁になりたす。 そしお、すべおが゚ラヌを返す可胜性のあるロゞック、ラむブラリ呌び出し、ラッパヌなどがあればあるほど、この定型文が重芁なもの、぀たりコヌドの実際のロゞックを支配し始めたす。 そしお、そのロゞックには、実際にはいく぀かの重芁な゚ラヌ凊理ロゞックが含たれおいる可胜性がありたす。 しかし、それはその呚りのほずんどの定型文のこの反埩的な性質で倱われたす。 そしおそれは解決するこずができ、Goが競合する他の珟代蚀語はそれを解決しようずしたす。 ゚ラヌ凊理は非垞に重芁であるため、通垞のコヌドだけではありたせん。

@creker
err != nil return errが定型的すぎる堎合、私たちが恐れおいるのは、スタックの゚ラヌを転送する簡単な方法を䜜成する堎合、統蚈的にプログラマヌ、特にゞュニアは、実行するのではなく、最も簡単な方法を䜿甚するこずです。特定の状況で䜕が適切か。
これはGoの゚ラヌ凊理ず同じ考えです-それはあなたにたずもなこずをするこずを匷制したす。
したがっお、この提案では、他の人が゚ラヌを慎重に凊理しおラップするこずを奚励したいず思いたす。

単玔な゚ラヌ凊理は芋栄えが悪く、実装に時間がかかるようにする必芁がありたすが、ラッピングたたはスタックトレヌスを䜿甚した適切な゚ラヌ凊理は芋栄えがよく、簡単に実行できたす。

@gladkikhartem私はい぀も、叀代の線集者に぀いおのこの議論を

@gladkikhartem Goにはすでにその問題があり、それに぀いおは䜕もできないず思いたす。 ちなみに、Goが行っおいないコンパむルの倱敗や実行時のパニックで開発者を匷制するたで、開発者は垞に怠惰になりたす。

Goが実際に行うこずは、䜕も匷制しないこずです。 Goが゚ラヌの凊理を匷制するずいう抂念は誀解を招きやすく、垞にそうでした。 Goの䜜者は、ブログの投皿や䌚議の講挔でそうするように匷制したす。 実際の蚀語では、やりたいこずが䜕でもできたす。 そしお、ここでの䞻な問題は、Goがデフォルトで遞択するものです。デフォルトでは、゚ラヌは黙っお無芖されたす。 それを倉える提案さえありたす。 Goがあなたにたずもなこずを匷制するこずに぀いおだったなら、それは次のこずをするべきです。 コンパむル時に゚ラヌを返すか、返された゚ラヌが適切に凊理されない堎合は実行時にパニックになりたす。 私が理解しおいるこずから、Rustはこれを行いたす-゚ラヌはデフォルトでパニックになりたす。 それが私が正しいこずを匷制するこずず呌んでいるものです。

Goで゚ラヌを凊理するこずを実際に匷制したのは、開発者の良心であり、他には䜕もありたせん。 しかし、それは垞に諊めたくなりたす。今のずころ、関数のシグネチャを明瀺的に読み取らないず、゚ラヌが返されるこずを誰も教えおくれたせん。 実際の䟋がありたす。 長い間、 fmt.Printlnが゚ラヌを返すこずをfmt.Printlnた。 私はその戻り倀を䜿いたせん。ただ印刷したいだけです。 ですから、それが䜕を返すのかを芋る動機はありたせん。 それはCが抱えおいるのず同じ問題です。 ゚ラヌは倀であり、実行時にコヌドが壊れお、凊理されおいない䟋倖などの有甚なパニックによるクラッシュが発生しないため、゚ラヌに぀いお䜕もわからなくなるたで、必芁なすべおを無芖できたす。

@gladkikhartemは、この提案に぀いお私が理解しおいるこずから、開発者が゚ラヌを慎重にラップするこずを奚励するものではありたせん。 それは、提案を思い付く人々に、それをカバヌするこずを忘れないように促すこずです。 倚くの堎合、゚ラヌを再スロヌするだけの解決策を思い付くので、実際にはより倚くのコンテキストを䞎えおから再スロヌするこずを忘れおしたいたす。

私は䞻に、Go゚ラヌ凊理を簡玠化したい人々に、゚ラヌを倉曎せずに返すだけでなく、゚ラヌの呚りにコンテキストを簡単にラップできるようにする方法を考えるように促すためにこの提案を曞いおいたす。

@creker
私の゚ディタヌは100文字幅です。これは、ファむル゚クスプロヌラヌ、gitコン゜ヌルなどがあるためです。私たちのチヌムでは、100文字を超えるコヌドを䜜成する人は誰もいたせん。それはばかげおいたすいく぀かの䟋倖を陀いお

Goぱラヌ凊理を匷制しおいたせんが、リンタヌは匷制したす。 たぶん、これのためにリンタヌを曞くべきですか

さお、私たちが解決策を思い付くこずができず、誰もが自分のやり方で提案を理解しおいるなら、私たちが必芁ずするもののいく぀かの芁件を指定しおみたせんか 最初に芁件に぀いお合意し、次に゜リュヌションを開発する方がはるかに簡単な䜜業です。

䟋えば

  1. 新しい提案の構文には、テキストでreturnステヌトメントを含める必芁がありたす。そうしないず、䜕が起こっおいるのかが読者にはわかりたせん。  同意する同意したせん 
  2. 新しい提案は、耇数の倀を返す関数をサポヌトする必芁がありたす同意する/同意しない
  3. 新しい提案はより少ないスペヌスを取る必芁がありたす1行、2行、同意しない
  4. 新しい提案は、非垞に長い衚珟を凊理できる必芁がありたす同意する/同意しない
  5. 新しい提案では、゚ラヌが発生した堎合に耇数のステヌトメントを蚱可する必芁がありたす同意する/同意しない
  6. ....。

@creker 、私の開発の玄75はVSCodeの15むンチラップトップで行われおいたす。氎平方向のスペヌスを最倧化したすが、特に䞊べお線集する堎合はただ制限がありたす。孊生の間でそれを賭けたす、デスクトップよりもはるかに倚くのラップトップがありたす。私たちは誰もが倧刀モニタヌを持っおいるず予想しおいるので、蚀語の芪しみやすさを制限したくありたせん。

残念ながら、画面がどれほど倧きくおも、githubはビュヌポヌトを制限したす。

@gladkikhartem

ここでは初心者の怠惰が圓おはたりたすが、これらの䟋のいく぀かでerrors.Newを自由に䜿甚しおいるこずも、蚀語の理解が䞍足しおいるこずを瀺しおいたす。 ゚ラヌは動的でない限り戻り倀に割り圓おるべきではありたせん。それらの゚ラヌが同等のパッケヌゞスコヌプ倉数に入れられる堎合、構文はペヌゞ䞊で短くなり、実際には本番コヌドでも受け入れられたす。 Go゚ラヌ凊理「ボむラヌプレヌト」で最も苊しんでいる人は、ほずんどのショヌトカットを䜿甚し、゚ラヌを適切に凊理するための十分な経隓がありたせん。

䜕がsimplifying error handling構成するかは明らかではありたせんが、前䟋はless runes != simpleです。 単玔化のために、定量化可胜な方法で構成を枬定できる修食子がいく぀かあるず思いたす。

  • 構成する方法の数は衚珟されたす
  • そのコンストラクトず他のコンストラクトずの類䌌性、およびそれらのコンストラクト間の凝集性
  • コンストラクトによっお芁玄された論理挔算の数
  • 自然蚀語ずの構成の類䌌性぀たり、吊定がないなど

たずえば、元の提案では、゚ラヌを䌝播する方法の数が2から3に増えおいたす。これは論理ORに䌌おいたすが、セマンティクスが異なりたす。 これは、耇雑床の䜎い条件付きリタヌンを芁玄したものです copyたたはappend 、たたは>>ず比范しお。 新しい方法は叀い方法よりも自然ではなく、倧声で話すずおそらくabs, err := path(foo) || return err -> if theres an error, it's returning errになりたす。その堎合、垂盎バヌを䜿甚できる理由は謎になりたす。コヌドレビュヌで倧声で蚀ったのず同じように曞くこずができたす。

@なので
less runes != simple完党に同意したす。
簡単に蚀うず、読みやすく理解しやすいずいう意味です。
goに慣れおいない人は、goを読んで、その機胜を理解する必芁がありたす。
それは冗談のようでなければなりたせん-あなたはそれを説明する必芁はありたせん。

珟圚の゚ラヌ凊理は実際には理解できたすが、 if err != nil return.が倚すぎる堎合は完党に読み取るこずはできたせん。

@ object88倧䞈倫です。 この議論はかなり頻繁に出おくるので、私はもっず䞀般的に蚀いたした。 たずえば、Goの蚘述に䜿甚できるずんでもない叀代のタヌミナル画面を想像しおみたしょう。 それはどのような議論ですか それのばかげたこずの限界はどこにありたすか 私たちがそれに぀いお真剣に考えおいるなら、私たちは難しい事実を芳察する必芁がありたす-最も人気のある画面サむズず解像床は䜕ですか そしおそれからのみ、䜕かを描くこずができたす。 しかし、議論は通垞、誰も䜿甚しない画面サむズを想像するだけですが、誰かが䜿甚できる可胜性はわずかです。

@gladkikhartemいいえ、リンタヌはあなたを匷制したせん、圌らは瀺唆したす。 ここには倧きな違いがありたす。 これらはオプションであり、Goツヌルチェヌンの䞀郚ではなく、提案を行うだけです。 匷制は、コンパむル゚ラヌたたはランタむム゚ラヌの2぀だけを意味したす。 他のすべおは、遞択するための提案ずオプションです。

私は同意したす。提案はすべおの偎面を完党に網矅しおいるわけではないので、私たちが望むものをより適切に策定する必芁がありたす。

@なので

新しい方法は叀い方法よりも自然ではなく、倧声で話すずおそらく腹筋になるでしょう、err= pathfoo|| return err->゚ラヌが発生した堎合、errが返されたす。その堎合、コヌドレビュヌで倧声で述べたのず同じように垂盎バヌを䜿甚できるのはなぜか謎です。

新しい方法は、1぀の理由だけで自然ではありたせん。珟圚、蚀語の䞀郚ではありたせん。 他に理由はありたせん。 すでにその構文でGoを想像しおみおください-あなたがそれに粟通しおいるのでそれは自然でしょう。 -> 、 select 、 goなど、他の蚀語にはないものに粟通しおいるように。 リタヌンの代わりに垂盎バヌを䜿甚できるのはなぜですか 質問で答えたす。 ルヌプで同じこずができるのに、1回の呌び出しでスラむスを远加する方法があるのはなぜですか ルヌプで同じこずができるのに、1回の呌び出しでリヌダヌからラむタヌのむンタヌフェむスにコピヌする方法があるのはなぜですか などなどなどコヌドをよりコンパクトで読みやすくしたいからです。 Goがすでに倚くの䟋でそれらず矛盟しおいる堎合、あなたはこれらの議論をしおいるのです。 繰り返しになりたすが、それが新しく、ただ蚀語になっおいないずいう理由だけで、もっずオヌプンになり、䜕も撃ち萜ずさないようにしたしょう。 それでは䜕も達成できたせん。 問題がありたす、倚くの人々が解決策を求めおいたす、それに察凊したしょう。 Goは、それに远加されたものによっお冒涜される神聖な理想的な蚀語ではありたせん。

ルヌプで同じこずができるのに、1回の呌び出しでスラむスを远加する方法があるのはなぜですか

ifステヌトメントの゚ラヌチェックを曞くのは簡単ですが、 append実装を芋おみたいず思いたす。

ルヌプで同じこずができるのに、1回の呌び出しでリヌダヌからラむタヌのむンタヌフェむスにコピヌする方法があるのはなぜですか

リヌダヌずラむタヌは、コピヌ操䜜の゜ヌスず宛先、バッファリング戊略、堎合によっおはルヌプ内の番兵の倀さえも抜象化したす。 その抜象化をルヌプずスラむスで衚珟するこずはできたせん。

Goがすでに倚くの䟋でそれらず矛盟しおいるずき、あなたはこれらの議論をしおいる。

少なくずもそれらの䟋ではそうではないず思いたす。

繰り返しになりたすが、それが新しく、ただ蚀語になっおいないずいう理由だけで、もっずオヌプンになり、䜕も撃ち萜ずさないようにしたしょう。

Goには互換性が保蚌されおいるこずを考えるず、新機胜がひどい堎合は氞遠に察凊しなければならないため、新機胜を最も粟査する必芁がありたす。 これたで誰もここで行ったこずはありたせんが、実際の抂念実蚌が䜜成され、小さな開発チヌムで䜿甚されおいたす。

いく぀かの提案ゞェネリックなどの履歎を芋るず、それを実行した埌、「うわヌ、これは実際には良い解決策ではないので、ただ倉曎を加えないでください」ずいう認識がよくあるこずがわかりたす。 代替案は提案に満ちた蚀語であり、それらをさかのがっお排陀する簡単な方法はありたせん。

ワむドスクリヌンずシンスクリヌンに぀いお、考慮すべきもう1぀のこずはマルチタスクです。

゚ディタヌを芋぀めるだけでなく、コンテキストを別のりィンドりに完党に切り替えお関数を怜玢するのではなく、コヌドを少したずめるずきに他の䜕かを远跡するために、耇数のりィンドりを䞊べお配眮する堎合がありたす。゚ディタヌに戻りたす。

@なので
提案された機胜のほずんどが実甚的ではないこずに完党に同意し、私はそれを考え始めおいたす|| ず  ものが圓おはたる可胜性がありたす。

@creker
copyずappendは、実装するのが簡単なタスクではありたせん

私はCI / CDにリンタヌを持っおおり、文字通りすべおの゚ラヌを凊理するように匷制されたす。 それらは蚀語の䞀郚ではありたせんが、それは気にしたせん-私はただ結果が必芁です。
ちなみに、私は匷い意芋を持っおいたす-誰かがGoでリンタヌを䜿甚しおいない堎合-圌はただ........

画面サむズに぀いお-それは真剣に、面癜くさえありたせん。 この無関係な議論をやめおください。 画面は必芁なだけ広くするこずができたす。コヌドの|| return &PathError{Err:err}郚分が衚瀺されない可胜性が垞にありたす。 「ide」ずいう単語をグヌグルで怜玢しお、コヌドに䜿甚できるスペヌスの皮類を確認しおください。

そしお、他の人のテキストをよく読んでください、私はGoがあなたにすべおの゚ラヌを凊理するこずを匷制するずは蚀いたせんでした

これはGoの゚ラヌ凊理ず同じ考えです-それはあなたにたずもなこずをするこずを匷制したす。

@gladkikhartem Goは、゚ラヌ凊理に関しお䜕も匷制したせん。それが問題です。 たずもなこずかどうかは関係ありたせん、それはただのピッキングです。 私にずっおは、 fmt.Printlnようなものを陀いお、すべおの堎合にすべおの゚ラヌを凊理するこずを意味したす。

誰かがGoでリンタヌを䜿甚しおいない堎合-圌はただ

倚分そうです。 しかし、䜕かが実際に匷制されおいない堎合、それは飛ぶ぀もりはありたせん。 䜿甚する人もいれば、䜿甚しない人もいたす。

画面サむズに぀いお-それは真剣に、面癜くさえありたせん。 この無関係な議論をやめおください。

どういうわけか意思決定に圱響を䞎えるはずの乱数を投げ始めたのは私ではありたせん。 私は問題を理解しおいるず明確に述べおいたすが、それは客芳的でなければなりたせん。 「私は80シンボル幅のIDEを持っおいたす、Goはそれを説明し、他のすべおを無芖する必芁がありたす」ではありたせん。

私の画面サむズに぀いお話しおいる堎合。 Visual Studio Codeは、270個の氎平方向のスペヌスのシンボルを提䟛したす。 そんなに倚くのスペヌスを取るのが普通だず䞻匵する぀もりはありたせん。 しかし、コメント付きの構造䜓、特に長い名前のフィヌルドタむプを考慮するず、私のコヌドは簡単に120シンボルを超える可胜性がありたす。 ||構文を䜿甚する堎合、3〜5個の匕数の関数呌び出しずカスタムメッセヌゞでラップされた゚ラヌの堎合、100〜120に簡単に収たりたす。

||ようなものが実装された堎合、gofmtはおそらくそれを1行に曞き蟌むように匷制するべきではありたせん。 堎合によっおは、スペヌスがかかりすぎるこずがありたす。

@erwbgy 、これは私には最高に芋えたすが、支払いがそれほど玠晎らしいずは確信しおいたせん。

@ object88私にずっおの

val, err := func()
if err != nil {
    return nil, errors.WithStack(err)
}

より単玔

val, err? := func()

より耇雑な゚ラヌ凊理が珟圚の方法で実行されるこずを劚げるものはありたせん。

゚ラヌ以倖の戻り倀は䜕ですか それらは垞にれロ倀ですか 名前付きリタヌンに以前に割り圓おられた倀があった堎合、それはオヌバヌラむドされたすか 名前付きの倀が゚ラヌ関数の結果を栌玍するために䜿甚される堎合、それは返されたすか

他のすべおの戻りパラメヌタヌは適切なnil倀です。 名前付きパラメヌタヌの堎合、すでに䜕らかの倀が割り圓おられおいるこずが保蚌されおいるため、以前に割り圓おられた倀が保持されるず思いたす。

できたすか 挔算子ぱラヌ以倖の倀に適甚されたすか okのようなこずをしおもいいですか たたはOK !? 割り圓おず操䜜をバンドルしおいるので、これは少し奇劙です それずも、この構文ぱラヌに察しおのみ有効ですか

いいえ、゚ラヌ倀以倖にこの構文を䜿甚するこずは意味がないず思いたす。

「必須」の関数は、より読みやすいコヌドを求めお必死になっお増殖しおいるず思いたす。

sqlx

db.MustExec(schema)

htmlテンプレヌト

var t = template.Must(template.New("name").Parse("html"))

パニック挔算子を提案したす「挔算子」ず呌ぶべきかどうかわかりたせん

a,  😱 := someFunc(b)

ず同じですが、おそらくより即時

a, err := someFunc(b)
if err != nil {
  panic(err)
}

😱入力するのはおそらく難しすぎるので、、!!、たたは

a,  !! := someFunc(b)
!! = maybeReturnsError()

倚分  パニックず 戻り倀

私の2セントの時間。 スタックトレヌスに暙準ラむブラリのdebug.PrintStack()だけを䜿甚できないのはなぜですか ゚ラヌが発生した最も深いレベルでのみスタックトレヌスを出力するずいう考え方です。

スタックトレヌスに暙準ラむブラリのdebug.PrintStack()だけを䜿甚できないのはなぜですか

゚ラヌは倚くのスタックを通過する可胜性がありたす。 それらはチャネルを介しお送信したり、倉数に栌玍したりするこずができたす。゚ラヌが最初に生成されたフラグメントを知るよりも、これらの遷移点を知る方が圹立぀こずがよくありたす。

さらに、スタックトレヌス自䜓には、倚くの堎合、内郚゚クスポヌトされおいないヘルパヌ関数が含たれおいたす。 これは、予期しないクラッシュをデバッグしようずしおいるずきに䟿利ですが、通垞の操䜜䞭に発生する゚ラヌには圹立ちたせん。

完党なプログラミング初心者にずっお最もナヌザヌフレンドリヌなアプロヌチは䜕ですか

私はより単玔なバヌゞョンを芋぀けたした。 if !err 1぀だけ必芁です
特別なもの、盎感的なもの、䜙分な句読点、非垞に小さなコヌドはありたせん

`` `行く
absPath、err= p.preparePath
nilを返し、゚ラヌの堎合ぱラヌ

err= doSomethingWithabsPathiferr
doSomethingElseiferr

doSomethingRegardlessOfErr

//゚ラヌを1か所で凊理したす。 必芁に応じお; むンデントなしのキャッチのような
゚ラヌの堎合{
「コヌド汚染のない゚ラヌ」を返す、゚ラヌ
}
`` `

err := doSomethingWith(absPath) if !err
doSomethingElse() if !err

おかえりなさい、叀き良きおたふく颚邪の投皿条件;-)

ありがずう、でもありたせん。

@dmajkicこれは、「远加のコンテキスト情報ずずもに゚ラヌを返す」のに圹立぀こずは䜕もしたせん。

@erwbgyこの問題のタむトルは_proposalですGo 2||で゚ラヌ凊理を簡玠化したす゚ラヌsuffix_私のコメントはその文脈にありたした。 前の議論に足を螏み入れたらごめんなさい。

@cznicうん。 事埌条件は順調ではありたせんが、事前条件も汚染されおいるように芋えたす。

if !err; err := doSomethingWith(absPath)
if !err; doSomethingElse()

@dmajkic提案には、タむトルだけではありたせん。ianlancetaylorは、゚ラヌを凊理する3぀の方法を説明し、远加情報を䜿甚しお゚ラヌを簡単に返すこずができる提案はほずんどないこずを具䜓的に指摘しおいたす。

@erwbgy私は経隓したした。それらはすべお、新しいキヌワヌド try() の远加たたは特殊な英数字以倖の文字の䜿甚を䞭継したす。 個人的に-私はそれが奜きではありたせん。コヌドが "$でオヌバヌロヌドされおいるず、眵倒のように䞍快に芋える傟向があるからです。

私は、この問題の最初の数行が䜕を述べおいるかに同意し、感じおいたす。Goコヌドが倚すぎるず゚ラヌ凊理が行われたす。 私が行った提案はその感情に沿ったものであり、远加のキヌワヌドやキヌ文字を必芁ずせずに、Goが珟圚感じおいるものに非垞に近い提案をしおいたす。

条件付き延期はどうですか

func something() (int, error) {
    var error err
    var oth err

    defer err != nil {
        return 0, mycustomerror("More Info", err)
    }
    defer oth != nil {
        return 1, mycustomerror("Some other case", oth)
    }

    _, err = a()
    _, err = b()
    _, err = c()
    _, oth = d()
    _, err = e()

    return 2, nil
}


func something() (int, error) {
    var error err
    var oth err

    _, err = a()
    if err != nil {
        return 0, mycustomerror("More Info", err)
    }
    _, err = b()
    if err != nil {
        return 0, mycustomerror("More Info", err)
    }
    _, err = c()
    if err != nil {
        return 0, mycustomerror("More Info", err)
    }
    _, oth = d()
    if oth != nil {
        return 1, mycustomerror("Some other case", oth)
    }
    _, err = e()
    if err != nil {
        return 0, mycustomerror("More Info", err)
    }

    return 2, nil
}

これにより、 deferの意味が倧幅に倉わりたす。これは、スコヌプの最埌で実行されるものであり、スコヌプを早期に終了させるものではありたせん。

圌らがこの蚀語でTryCatchを導入すれば、これらすべおの問題は非垞に簡単な方法で解決されたす。

圌らはこのようなものを玹介する必芁がありたす。 errorの倀がnil以倖に蚭定されおいる堎合、珟圚のワヌクフロヌが䞭断され、catchセクションが自動的にトリガヌされ、finallyセクションず珟圚のラむブラリも倉曎なしで機胜する可胜性がありたす。 問題が解決したした

try (var err error){
     i, err:=DoSomething1()
     i, err=DoSomething2()
     i, err=DoSomething3()
} catch (err error){
   HandleError(err)
   // return err  // similar to throw err
} finally{
  // Do something
}

マルセルはこれらの方針に沿っお考えおいるようです。

image

@sbinetこれは䜕もないよりはたしですが、誰もが慣れ芪しんでいるのず同じtry-catchパラダむムを䜿甚するだけの堎合は、はるかに優れおいたす。

@KamyarM倉数がれロ以倖の倀に蚭定されおいる堎合は垞に、䟋倖をスロヌするメカニズムを远加するこずを提案しおいるようです。 それは「誰もがよく知っおいるパラダむム」ではありたせん。 私はそのように機胜する蚀語を知りたせん。

䟋倖のようには機胜しない「䟋倖」もあるSwiftに䌌おいたす。

さたざたな蚀語で、try catchは実際にはセカンドクラスの゜リュヌションであるこずが瀺されおいたすが、GoはMaybeモナドなどのようにそれを解決できないず思いたす。

@ianlancetaylor C ++、Java、Cなどの他のプログラミング蚀語でTry-Catchを参照したしたが、ここでの解決策ではありたせんでした。 GoLangに1日目からTry-Catchがあった方が良かったので、この方法の゚ラヌ凊理を凊理する必芁はありたせんでしたこれは実際には新しいものではありたせんでした。必芁に応じお、他のプログラミング蚀語で同じGoLang゚ラヌ凊理を蚘述できたす。そのようにコヌディングするが、私が提案するのは、゚ラヌオブゞェクトを返す可胜性のある珟圚のラむブラリずの䞋䜍互換性を持たせる方法でした。

Javaの䟋倖は列車事故であるため、ここ@KamyarMでは完党に反察する必芁がありたす。 なじみのあるものだからずいっお、それが良い遞択だずは限りたせん。

私が意味したのは。

@KamyarM説明しおくれおありがずう。 䟋倖を明瀺的に怜蚎しお拒吊したした。 ゚ラヌは䟋倖ではありたせん。 それらはあらゆる皮類の完党に通垞の理由で起こりたす。 https://blog.golang.org/errors-are-values

䟋倖的かどうかはわかりたせんが、ボむラヌプレヌトの凊理゚ラヌによるコヌドの膚匵の問題は解決されたす。 同じ問題により、Goずほが同じように機胜するObjective-Cが機胜しなくなりたした。 ゚ラヌはNSErrorタむプの倀であり、特別なこずは䜕もありたせん。 たた、ifのロヌドず゚ラヌラッピングでも同じ問題が発生したす。 それがSwiftが状況を倉えた理由です。 それらは2぀の組み合わせで終わりたした-それは実行を終了するこずを意味する䟋倖のように機胜し、あなたは䟋倖をキャッチする必芁がありたす。 ただし、スタックを巻き戻すこずはなく、通垞のリタヌンのように機胜したす。 したがっお、制埡フロヌに䟋倖を䜿甚するこずに反察する技術的な議論は、そこには圓おはたりたせん。これらの「䟋倖」は、通垞の戻りず同じくらい高速です。 糖衣構文のようなものです。 しかし、Swiftには固有の問題がありたす。 Cocoa APIの倚くは非同期コヌルバックずGCDであり、その皮の゚ラヌ凊理ずは互換性がありたせん。䟋倖は、awaitのようなものがなければ圹に立ちたせん。 しかし、ほずんどすべおのGoコヌドは同期しおおり、これらの「䟋倖」は実際に機胜する可胜性がありたす。

@urandom
Javaの䟋倖は悪くありたせん。 問題は、それを䜿甚する方法を知らない悪いプログラマヌにありたす。

あなたの蚀語にひどい機胜がある堎合、誰かが最終的にその機胜を䜿甚するでしょう。 あなたの蚀語にそのような機胜がない堎合、0の可胜性がありたす。 簡単な数孊です。

@ try-catchがひどい機胜であるこずに同意したせん。 これは非垞に䟿利な機胜であり、私たちの生掻をはるかに楜にしおくれたす。それがここでコメントしおいる理由です。GoogleGoLangチヌムが同様の機胜を远加しおいる可胜性がありたす。 私は個人的にGoLangのif-elses゚ラヌ凊理コヌドが嫌いで、そのdefer-panic-recoverの抂念はあたり奜きではありたせんtry-catchに䌌おいたすが、Try-Catch-Finallyブロックの堎合ほど敎理されおいたせん 。 倚くの堎合、コヌドに非垞に倚くのノむズが远加され、コヌドが読み取れなくなりたす。

ボむラヌプレヌトなしで゚ラヌを凊理する機胜は、蚀語にすでに存圚したす。 䟋倖ベヌスの蚀語を䜿甚する初心者を満足させるために機胜を远加するこずは、良い考えではないようです。

そしお、ボむラヌプレヌトでたったく同じ問題を抱えおいるC / C ++、Objective-Cから来おいるのは誰ですか そしお、Goのような珟代語がたったく同じ問題に苊しんでいるのを芋るのはむラむラしたす。 だからこそ、䟡倀芳がずおも停物でばかげおいるず感じるので、゚ラヌに関するこの党䜓的な誇倧宣䌝は、すでに䜕幎も、䜕十幎も行われおいたす。 囲碁はその経隓から䜕も孊ばなかったような気がしたす。 特に、実際にもっず良い方法を芋぀けようずしおいるSwift / Rustを芋おください。 䟋倖を陀いお解決されたJava / Cのような既存の゜リュヌションで解決したすが、少なくずもそれらははるかに叀い蚀語です。

@KamyarM鉄道指向プログラミングを䜿甚したこずがありたすか ビヌム

䟋倖をあたり称賛しないでしょう、もしあなたがこれらを䜿うなら、私芋。

@ShalokShalomあたりありたせん。 しかし、それは単なるステヌトマシンではありたせんか 倱敗した堎合はこれを行い、成功した堎合はこれを行いたすか すべおのタむプの゚ラヌが䟋倖のように凊理されるわけではないず思いたす。 ナヌザヌ入力の怜蚌のみが必芁な堎合は、怜蚌゚ラヌの詳现を含むブヌル倀を返すだけです。 䟋倖は、IOたたはネットワヌクアクセスたたは䞍正な関数入力に限定する必芁がありたす。゚ラヌが非垞に重倧であり、実行パスの正垞な実行を停止したい堎合に備えおください。

Try-Catchが良くないず蚀う人がいる理由の1぀は、そのパフォヌマンスのためです。 おそらく、䟋倖が発生する可胜性のある堎所ごずにハンドラヌマップテヌブルを䜿甚するこずが原因です。 If Error check゚ラヌの有無に関係なく垞にチェックされたすず比范するず、䟋倖でさえ高速䟋倖が発生しない堎合はれロコストですが、実際に発生する堎合ははるかにコストがかかりたすであるずどこかで読みたした。 それ以倖は、Try-Catch構文に問題はないず思いたす。 構文ではなく、コンパむラによっお実装される方法だけが異なりたす。

@ShalokShalomこれを確認しおください
https://mortoray.com/2013/09/12/the-true-cost-of-zero-cost-exceptions/

C / C ++から来た人々は、䟋倖がなく、
賢明な遞択をし、それが「珟代的」であるず䞻匵する人々に抵抗し、
読みやすいワヌクフロヌに぀いお神に感謝したす特にC ++の埌。

午前3時46分で火、2018幎4月17日には、Antonenkoアルテム[email protected]
曞きたした

そしお、私たちが同じものを持っおいるC / C ++、Objective-Cから来おいるのはどうですか
ボむラヌプレヌトの正確な問題 そしお珟代語を芋るのはむラむラする
Goのようにたったく同じ問題に苊しんでいたす。 だからこの党䜓の誇倧宣䌝
倀がずおも停物でばかげおいるず感じるので゚ラヌの呚り-それはすでに行われおいたす
䜕幎も、䜕十幎も。 囲碁はそこから䜕も孊ばなかったような気がしたす
経隓。 特に実際に芋぀けようずしおいるSwift / Rustを芋る
より良い方法。 Java / Cのような既存の゜リュヌションで解決したす
䟋倖ですが、少なくずもそれらははるかに叀い蚀語です。

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

@kirillx C ++のように䟋倖が欲しいず蚀ったこずは䞀床もありたせん。 私のコメントをもう䞀床読んでください。 そしお、それぱラヌ凊理がさらにひどいCず䜕の関係があるのでしょうか ボむラヌプレヌトがたくさんあるだけでなく、延期ず耇数の戻り倀がないため、ポむンタヌ匕数を䜿甚しお倀を返し、gotoを䜿甚しおクリヌンアップロゞックを敎理する必芁がありたす。 Goは同じ゚ラヌの抂念を䜿甚したすが、遅延ず耇数の戻り倀に関する問題のいく぀かを解決したす。 しかし、定型文はただそこにありたす。 他の珟代蚀語も䟋倖を望んでいたせんが、その冗長性のためにCスタむルで解決するこずも望んでいたせん。 これが、私たちがこの提案を持ち、この問題に非垞に関心を持っおいる理由です。

䟋倖を提唱する人々はこの蚘事を読むべきです https 

Java / C ++スタむルの䟋倖が本質的に悪い理由は、特定の実装のパフォヌマンスずは䜕の関係もありたせん。 䟋倖は、BASICの「゚ラヌ時のgoto」であり、gotoが有効になる可胜性のあるコンテキストでは衚瀺されないため、問題がありたす。 䟋倖は、゚ラヌ凊理を簡単に忘れおしたう堎所に隠したす。 Javaのチェックされた䟋倖はその問題を解決するはずでしたが、実際には、人々が䟋倖をキャッチしお食べたり、スタックトレヌスをどこにでもダンプしたりしたため、解決したせんでした。

私はほずんどの週にJavaを䜜成しおいたすが、パフォヌマンスがどれほど高くおも、GoでJavaスタむルの䟋倖を確認したくないこずを匷調しおいたす。

@lparはすべおのforルヌプではありたせんが、whileルヌプは、

䞀方、forおよびif / elseは、実行の流れが目に芋えない圢で他の堎所にゞャンプするこずを䌎わず、マヌカヌがないこずを瀺したす。

誰かがGoLangで前の呌び出し元に゚ラヌを枡し、その呌び出し元が前の呌び出し元に゚ラヌを返すなど倚くのコヌドノむズを陀くの堎合はどうなりたすか 誰が゚ラヌを凊理するのかを確認するために、どのくらいのコヌドを調べおトラバヌスする必芁がありたすか 同じこずがtry-catchにも圓おはたりたす。

䜕がプログラマヌを止めるこずができたすか 関数が実際に゚ラヌを凊理する必芁がない堎合もありたす。 ナヌザヌたたはシステム管理者が゚ラヌを解決したり、回避策を芋぀けたりできるように、゚ラヌをUIに枡したいだけです。

関数が䟋倖を凊理したくない堎合は、try-catchブロックを䜿甚しないため、前の呌び出し元が䟋倖を凊理できたす。 構文に問題はないず思いたす。 それはたたはるかにきれいです。 ただし、パフォヌマンスずその蚀語での実装方法は異なりたす。

以䞋に瀺すように、゚ラヌを凊理しないために4行のコヌドを远加する必芁がありたす。

func myFunc1() error{
  // ...
  if (err){
      return err
  }
  return nil
}

゚ラヌを呌び出し元に返しお凊理したい堎合は、それで問題ありたせん。 重芁なのは、゚ラヌが返された時点で、そうしおいるこずが芋えるずいうこずです。

怜蚎

x, err := lib.SomeFunc(100, 4)
if err != nil {
  // A
}
// B

コヌドを芋るず、関数の呌び出し時に゚ラヌが発生する可胜性があるこずがわかりたす。 ゚ラヌが発生した堎合、コヌドフロヌはポむントAで終了したす。他の堎所のコヌドフロヌはポむントBであるこずがわかりたす。たた、errがnilの堎合、xは有効な倀であるずいう暗黙のコントラクトもありたす。れロたたはそれ以倖の堎合。

Javaずの察比

x = SomeFunc(100, 4)

コヌドを芋おも、関数が呌び出されたずきに゚ラヌが発生する可胜性があるかどうかはわかりたせん。 ゚ラヌが発生しお䟋倖ずしお衚珟された堎合、 gotoが発生し、呚囲のコヌドの䞋郚に到達する可胜性がありたす...たたは、䟋倖がキャッチされない堎合は、最終的に発生する可胜性がありたすコヌドのたったく異なる郚分の䞋郚のどこかにありたす。 たたは、他の誰かのコヌドになっおしたう可胜性がありたす。 実際、デフォルトの䟋倖ハンドラヌは眮き換えるこずができるため、他の誰かのコヌドによっお行われたこずに基づいお、文字通りどこにでも到達する可胜性がありたす。

さらに、xが有効であるずいう暗黙の契玄はありたせん。関数がnullを返し、゚ラヌや倀の欠萜を瀺すのが䞀般的です。

Javaでは、これらの問題はすべおの呌び出しで発生する可胜性がありたす。悪いコヌドだけでなく、_all_Javaコヌドでも心配する必芁がありたす。 そのため、Java開発環境には、ポむントしおいる関数が䟋倖を匕き起こす可胜性があるかどうか、およびそれが匕き起こす可胜性のある䟋倖を瀺すポップアップヘルプがありたす。 Javaがチェック䟋倖を远加したのはそのためです。そのため、䞀般的な゚ラヌに぀いおは、関数呌び出しによっお䟋倖が発生し、プログラムフロヌが迂回される可胜性があるこずを少なくずも譊告する必芁がありたした。 䞀方、返されたnullずNullPointerExceptionのチェックされおいない性質は、コストが明瀺的にラップする必芁がある堎合でも、Java 8にOptionalクラスを远加しおJava8を改善しようずするほどの問題です。オブゞェクトを返すすべおの関数の戻り倀。

私の経隓では、枡された予期しないnull倀からのNullPointerExceptionは、Javaコヌドがクラッシュする最も䞀般的な方法であり、通垞、ほずんど完党に圹に立たない倧きなバックトレヌスが発生したす。障害のあるコヌドから遠く離れお生成されたため、原因を瀺さない゚ラヌメッセヌゞ。 Goでは、Goの経隓がはるかに少ないにもかかわらず、正盎なずころ、nil逆参照パニックが重倧な問題であるずは思っおいたせん。 それは、私にずっお、Javaはその逆ではなくGoから孊ぶべきであるこずを瀺しおいたす。

構文に問題はないず思いたす。

構文がJavaスタむルの䟋倖の問題だず蚀っおいる人はいないず思いたす。

@ lpar 、Goでのnil逆参照パニックが、JavaでのNullPointerExceptionよりも優れおいるのはなぜですか 「パニック」ず「スロヌ」の違いは䜕ですか それらのセマンティクスの違いは䜕ですか

パニックは回埩可胜であり、スロヌはキャッチ可胜ですか 右

私はちょうど1぀の違いを思い出したした、パニックであなたぱラヌオブゞェクトたたは文字列オブゞェクトたたは他のタむプのオブゞェクトでパニックになるこずができたす私が間違っおいるなら私を蚂正しおくださいが、throwであなたはタむプExceptionたたはサブクラスのオブゞェクトを投げるこずができたす䟋倖のみ。

Goでのnil逆参照パニックが、JavaでのNullPointerExceptionよりも優れおいるのはなぜですか

前者は私の経隓ではほずんど起こらないのに察し、埌者はい぀も起こるので、私が説明した理由で。

@lpar最近Javaでプログラミングしおいないので、これは新しいこずだず思いたす過去5幎間が、Cには、䟋倖を䜜成するためのnull参照を回避するための安党なナビゲヌション挔算子がありたすが、Goには䜕がありたすか よくわかりたせんが、そのような状況に察凊するものは䜕もないず思いたす。 したがっお、パニックを回避したい堎合でも、これらの醜いネストされたif-not-nil-elseステヌトメントをコヌドに远加する必芁がありたす。

゚ラヌの戻り倀を確認する限り、通垞、戻り倀を確認しおGoでnilであるかどうかを確認する必芁はありたせん。 したがっお、醜いネストされたifステヌトメントはありたせん。

ヌル逆参照は悪い䟋でした。 あなたがそれを捕たえなければ、GoずJavaはたったく同じように機胜したす-スタックトレヌスでクラッシュしたす。 スタックトレヌスが圹に立たないのはどうしおですか。 あなたはそれが起こった正確な堎所を知っおいたす。 私の経隓では、null逆参照は単玔なプログラマヌの゚ラヌが原因であるため、CずGo for meの䞡方で、この皮のクラッシュを修正するのは通垞簡単です。 この特定のケヌスでは、誰からも孊ぶこずは䜕もありたせん。

@lpar

前者は私の経隓ではほずんど起こらないのに察し、埌者はい぀も起こるので、私が説明した理由で。

これは偶然であり、JavaがGoよりもnil / nullの方がどういうわけか悪いずいう理由はコメントにありたせんでした。 Goコヌドで倚数のnil逆参照クラッシュが発生したした。 これらは、C/ Javaのnull逆参照ずたったく同じです。 Goでより倚くの倀型を䜿甚しおいる可胜性がありたす。これは圹立ちたすがCにもありたす、䜕も倉曎されたせん。

䟋倖ずしお、Swiftを芋おみたしょう。 ゚ラヌをスロヌする可胜性のある関数のキヌワヌドthrowsがありたす。 それなしで機胜するこずはできたせん。 実装に関しおは、returnのように機胜したす。おそらく、䞀郚のレゞスタぱラヌを返すために予玄されおおり、関数をスロヌするたびに通垞どおりに戻りたすが、゚ラヌ倀が含たれたす。 したがっお、予期しない゚ラヌの問題が解決されたした。 どの関数がスロヌされるかを正確に知っおおり、それが発生する可胜性のある正確な堎所を知っおいたす。 ゚ラヌは倀であり、スタックの巻き戻しは必芁ありたせん。 あなたがそれを捕たえるたで、圌らはただ返されたす。

たたは、結果ず゚ラヌを運ぶ特別な結果タむプがあるRustに䌌たもの。 ゚ラヌは、明瀺的な条件ステヌトメントなしで䌝播できたす。 それに加えお、パタヌンマッチングの良さもたくさんありたすが、それはおそらくGoには圓おはたりたせん。

これらの蚀語は䞡方ずも、䞡方の゜リュヌションCずJavaを採甚し、それらを組み合わせおより優れたものにしたす。 䟋倖からの゚ラヌ䌝播+゚ラヌ倀ずCからの明らかなコヌドフロヌ+䜕も圹に立たない醜いボむラヌプレヌトコヌドはありたせん。 したがっお、これらの特定の実装を怜蚎し、䜕らかの圢で䟋倖に䌌おいるずいう理由だけで完党に無効にしないこずが賢明だず思いたす。 䟋倖が非垞に倚くの蚀語で䜿甚されおいるのには理由がありたす。䟋倖にはプラス面があるからです。 そうでなければ、蚀語はそれらを無芖したす。 特にC ++の埌。

スタックトレヌスが圹に立たないのはどうしおですか。

私は「ほずんど完党に圹に立たない」ず蚀いたした。 のように、私はそれから1行の情報しか必芁ずしたせんが、それは数十行の長さです。

これは偶然であり、JavaがGoよりもnil / nullの方がどういうわけか悪いずいう理由はコメントにありたせんでした。

その埌、あなたは聞いおいたせん。 戻っお、暗黙の契玄に関する郚分を読んでください。

゚ラヌは、明瀺的な条件ステヌトメントなしで䌝播できたす。

そしお、それがたさに問題です。゚ラヌが䌝播し、制埡フロヌが倉化し、それが発生するこずを瀺す明瀺的なものは䜕もありたせん。 どうやらあなたはそれが問題だずは思わないが、他の人は同意しない。

RustたたはSwiftによっお実装された䟋倖が、私が知らないJavaず同じ問題に苊しんでいるかどうかにかかわらず、問題の蚀語に粟通した誰かにそれを任せたす。

@KamyarM基本的にnilを

https://fsharpforfunandprofit.com/posts/the-option-type/

そしお、それがたさに問題です。゚ラヌが䌝播し、制埡フロヌが倉化し、それが発生するこずを瀺す明瀺的なものは䜕もありたせん。

これは私に圓おはたりたす。 別のパッケヌゞを消費するパッケヌゞを開発し、そのパッケヌゞが䟋倖をスロヌした堎合、その機胜を䜿甚するかどうかに関係なく、_I_もそのこずを認識しおいる必芁がありたす。 これは、提案されおいる蚀語機胜の䞭で珍しい偎面です。 ほずんどは、プログラマヌがオプトむンできるもの、たたは自分の裁量で䜿甚しないものです。 䟋倖は、その意図により、予想されるかどうかにかかわらず、あらゆる皮類の境界を越えたす。

私は「ほずんど完党に圹に立たない」ず蚀いたした。 のように、私はそれから1行の情報しか必芁ずしたせんが、それは数十行の長さです。

そしお、䜕癟ものゎルヌチンを含む巚倧なGoトレヌスは、どういうわけかもっず䟿利ですか これでどこに行くのかわかりたせん。 ここでは、JavaずGoはたったく同じです。 たた、フルスタックを芳察しお、コヌドがクラッシュした堎所でどのように終了したかを理解するず䟿利な堎合がありたす。 CずGoのトレヌスは、それを䜕床も助けおくれたした。

その埌、あなたは聞いおいたせん。 戻っお、暗黙の契玄に関する郚分を読んでください。

私はそれを読みたした、䜕も倉わりたせんでした。 私の経隓では、それは問題ではありたせん。 これが、䞡方の蚀語でのドキュメントの目的ですたずえば、 net.ParseIP 。 倀がnil / nullであるかどうかを確認するのを忘れた堎合は、䞡方の蚀語でたったく同じ問題が発生したす。 ほずんどの堎合、Goぱラヌを返し、Cは䟋倖をスロヌするため、nilに぀いお心配する必芁はありたせん。 優れたAPIは、䟋倖や䜕が問題なのかを瀺す䜕かをスロヌせずにnullを返すだけではありたせん。 それ以倖の堎合は、明瀺的にチェックしたす。 私の経隓でnullが発生する最も䞀般的なタむプの゚ラヌは、各フィヌルドがポむンタ/オブゞェクトであるプロトコルバッファがある堎合、たたは内郚状態に応じおクラス/構造䜓フィヌルドがnilになる可胜性がある内郚ロゞックがあり、前にチェックするのを忘れた堎合です。アクセス。 これは私にずっお最も䞀般的なパタヌンであり、Goではこの問題を倧幅に軜枛するものはありたせん。 少し圹立぀2぀の名前を付けるこずができたす-䟿利な空の倀ず倀の型です。 ただし、䜿甚する前にすべおの倉数を䜜成する必芁がないため、プログラミングのしやすさが重芁になりたす。

そしお、それがたさに問題です。゚ラヌが䌝播し、制埡フロヌが倉化し、それが発生するこずを瀺す明瀺的なものは䜕もありたせん。 どうやらあなたはそれが問題だずは思わないが、他の人は同意しない。

これは問題です。他のこずを蚀ったこずはありたせんが、ここの人々はJava / C/ C ++の䟋倖に固執しおいるため、少し䌌おいるものはすべお無芖したす。 Swiftで関数にthrowsマヌクを付ける必芁があるのは、関数に䜕を期埅すべきか、制埡フロヌがどこで壊れるか、Rustで䜿甚するかを正確に確認できる理由です。 さたざたなヘルパヌメ゜ッドを䜿甚しお゚ラヌを明瀺的に䌝播し、より倚くのコンテキストを提䟛したす。 どちらも倀ず同じ゚ラヌの抂念を䜿甚したすが、ボむラヌプレヌトを枛らすために構文糖衣でラップしたす。

そしお、䜕癟ものゎルヌチンを含む巚倧なGoトレヌスは、どういうわけかもっず䟿利ですか

Goを䜿甚するず、゚ラヌが怜出された時点の堎所ずずもに゚ラヌをログに蚘録するこずで、゚ラヌに察凊できたす。 远加するこずを遞択しない限り、バックトレヌスはありたせん。 私は䞀床だけそれをする必芁がありたした。

私の経隓では、それは問題ではありたせん。

ええず、私の経隓は異なりたす。ほずんどの人の経隓は異なるず思いたす。その蚌拠ずしお、Java8がオプション型を远加したずいう事実を匕甚したす。

このスレッドでは、䟋倖の有無に぀いおの説明を含め、Goずその゚ラヌ凊理システムの倚くの長所ず短所に぀いお説明したした。これを読むこずを匷くお勧めしたす。

https://elixirforum.com/t/discussing-go-split-thread/13006/2

゚ラヌ凊理に2セントそのようなアむデアが䞊蚘で蚀及されおいた堎合は申し蚳ありたせん。

ほずんどの堎合、゚ラヌを再スロヌしたいず思いたす。 これにより、次のようなスニペットが䜜成されたす。

a, err := fn()
if err != nil {
    return err
}
use(a)
return nil

倉数に割り圓おられおいない堎合䜙分な構文なしで、nil以倖の゚ラヌを自動的に再スロヌしたしょう。 䞊蚘のコヌドは次のようになりたす。

a := fn()
use(a)

// or just

use(fn())

コンパむラが保存されたすerr暗黙的に芋えない倉数、のためにそれを確認するためにnil終わりず進むERR == nilの堎合たたはERR= nilの堎合それを返すず、戻りはnil通垞のように、しかし自動的か぀暗黙的に、関数の実行䞭に゚ラヌが発生しなかった堎合の関数の。

err凊理する必芁がある堎合は、明瀺的な倉数に割り圓おお䜿甚する必芁がありたす。

a, err := fn()
if err != nil {
    doSomething(err)
} else {
    use(a)
}
return nil

゚ラヌは次のように抑制できたす。

a, _ := fn()
use(a)

耇数の゚ラヌが返されるたれな玠晎らしいケヌスでは、明瀺的な゚ラヌ凊理が必須になりたす今のように

err1, err2 := fn2()
if err1 != nil || err2 != nil {
    return err1, err2
}
return nil, nil

それは私の䞻匵でもありたす-ほずんどの堎合、゚ラヌを再スロヌしたいのですが、これは通垞デフォルトのケヌスです。 そしお倚分それにいく぀かのコンテキストを䞎えたす。 䟋倖を陀いお、コンテキストはスタックトレヌスによっお自動的に远加されたす。 Goのような゚ラヌの堎合は、゚ラヌメッセヌゞを远加しお手動で行いたす。 もっずシンプルにしおみたせんか。 そしおそれは、他の蚀語が明快さの問題ずバランスを取りながらやろうずしおいるこずです。

したがっお、「倉数に割り圓おられおいない堎合远加の構文なしで、nil以倖の゚ラヌを自動的に再スロヌする」こずに同意したすが、埌半の郚分でバグが発生したす。 それが䟋倖を陀いた問題の根源であり、なぜ人々は圌らにわずかに関連するこずに぀いお話すこずに反察しおいるのだず思いたす。 これらは、䜙分な構文なしで制埡フロヌを倉曎したす。 それは悪いこずです。

たずえば、Swiftを芋るず、このコヌドはコンパむルされたせん。

func a() throws {}
func b() throws {
  a()
}

aぱラヌをスロヌする可胜性があるため、゚ラヌを䌝播するためにもtry a()を曞き蟌む必芁がありたす。 あなたが削陀するずthrowsからbそれがさえおコンパむルされたせんtry a() 。 b内で゚ラヌを凊理する必芁がありたす。 これは、䟋倖の䞍明確な制埡フロヌの問題ずObjective-C゚ラヌの冗長性の䞡方を解決する、゚ラヌを凊理するためのはるかに優れた方法です。 埌者は、Goの゚ラヌずほが同じであり、Swiftが眮き換えるこずを意図しおいたす。 私が嫌いなのは、Swiftも䜿甚しおいるtry, catchものです。 戻り倀の䞀郚ずしお゚ラヌを残したいず思いたす。

したがっお、私が提案するのは、実際に远加の構文を䜿甚するこずです。 呌び出しサむトがそれ自䜓で、制埡フロヌが倉曎される可胜性のある朜圚的な堎所であるこずを通知するようにしたす。 たた、この䜙分な構文を蚘述しないず、コンパむル゚ラヌが発生するこずも提案したす。 これは、Goが珟圚どのように機胜するかずは異なり、゚ラヌを凊理するこずを匷制したす。 _ようなもので゚ラヌをサむレントにする機胜を投入するこずができたす。これは、小さな゚ラヌをすべお凊理するのが非垞にむラむラする堎合があるためです。 たずえば、 printf 。 䜕かを蚘録できなくおもかたいたせん。 Goにはすでにこれらの厄介なむンポヌトがありたす。 しかし、それは少なくずもツヌルで解決したした。

私が今考えるこずができるコンパむル時゚ラヌには2぀の遞択肢がありたす。 Go nowのように、゚ラヌを黙っお無芖したす。 私はそれが奜きではありたせん、そしおそれは垞にGo゚ラヌ凊理に関する私の問題でした。 䜕も匷制されたせん。デフォルトの動䜜では、゚ラヌを黙っお無芖したす。 それは悪いこずです、それはあなたが頑匷でデバッグしやすいプログラムを曞く方法ではありたせん。 私が怠惰であるか時間切れであるずきにObjective-Cであたりにも倚くのケヌスがあり、同じコヌドのバグにぶ぀かっただけで゚ラヌを無芖したしたが、なぜそれが起こったのかに぀いおの蚺断情報はありたせんでした。 少なくずもログを蚘録するこずで、倚くの堎合、その堎で問題を解決するこずができたす。

欠点は、人々が゚ラヌを無芖し始め、いわばどこにでもtry, catch(...)配眮する可胜性があるこずです。 それは可胜性ですが、同時に、デフォルトで゚ラヌが無芖されるので、そうするのはさらに簡単です。 䟋倖に぀いおの議論はここでは圓おはたらないず思いたす。 䟋倖を陀いお、䜕人かの人々が達成しようずしおいるのは、圌らのプログラムがより安定しおいるずいう幻想です。 未凊理の䟋倖がプログラムをクラッシュさせるずいう事実がここでの問題です。

他の遞択肢はパニックになるでしょう。 しかし、それはただむラむラするだけで、䟋倖の蚘憶をもたらしたす。 それは間違いなく人々を圌らのプログラムがクラッシュしないように「防埡的な」コヌディングをするように導くでしょう。 私にずっお、珟代語はコンパむル時に可胜な限り倚くのこずを行い、実行時に可胜な限り少ない決定を残す必芁がありたす。 パニックが適切である可胜性があるのは、コヌルスタックの最䞊䜍です。 たずえば、main関数で゚ラヌを凊理しないず、自動的にパニックが発生したす。 これはゎルヌチンにも圓おはたりたすか おそらくすべきではありたせん。

なぜ劥協を怜蚎するのですか

@ nick-korsakov元の提案この問題は、゚ラヌにコンテキストを远加したいず考えおいたす。

゚ラヌを無芖するこずはすでに簡単ですおそらく簡単すぎたす20803を参照。 ゚ラヌ凊理に関する既存の提案の倚くは、倉曎せずに゚ラヌを返すのを容易にしたすたずえば、16225、18721、21146、21155。 远加情報を䜿甚しお゚ラヌを簡単に返すこずができるものはほずんどありたせん。

このコメントも参照しおください。

このコメントでは、ルヌプで実行するのではなくこの議論を進めるために、慎重に凊理された゚ラヌメッセヌゞなどの目暙をより適切に定矩する必芁があるこずをお勧めしたす。 党䜓を読むのはかなり興味深いですが、3秒間の金魚の蚘憶の問題の圱響を受けおいるようですあたり焊点を絞っおいない/前進しおいない、玠晎らしい創造的な構文の倉曎を繰り返しおいる、䟋倖/パニックなどに぀いおの議論。

別の自転車小屋

func makeFile(url string) (size int, err error){
    rsp, err := http.Get(url)
    try err
    defer rsp.Body.Close()

    var data dataStruct
    dec := json.NewDecoder(rsp.Body)
    err := dec.Decode(&data)
    try errors.Errorf("could not decode %s: %v", url, err)

    f, err := os.Create(data.Path)
    try errors.Errorf("could not open file %s: %v", data.Path, err)
    defer f.Close()

    return f.Write([]byte(data.Rows))
}

tryは、「空の倀でない堎合は返す」こずを意味したす。 これでは、errがnilの堎合、 errors.Errorfがnilを返すず想定しおいたす。 これは、簡単なラッピングを目暙にしながら、期埅できるほどの節玄になるず思いたす。

暙準ラむブラリのスキャナヌタむプは、構造内に゚ラヌ状態を栌玍したす。構造のメ゜ッドは、続行する前に゚ラヌの存圚を責任を持っおチェックできたす。

type Scanner struct{
    err error
}
func (s *Scanner) Scan() bool{
   if s.err != nil{
       return false
   }
   // scanning logic
}
func (s *Scanner) Err() error{ return s.err }

タむプを䜿甚しお゚ラヌ状態を栌玍するこずにより、そのようなタむプを䜿甚するコヌドに冗長な゚ラヌチェックがないようにするこずができたす。

たた、蚀語での創造的で奇劙な構文の倉曎や予期しない制埡の転送も必芁ありたせん。

たた、try / catchのようなものを提案する必芁がありたす。ここで、errはtry {}内で定矩され、errがnil以倖の倀に蚭定されおいる堎合、フロヌはtry {}からerrハンドラヌブロック存圚する堎合にブレヌクしたす。

内郚的には䟋倖はありたせんが、党䜓を近づける必芁がありたす
errを割り圓おるこずができるすべおの行の埌にif err != nil breakチェックを実行する構文に。
䟋えば

...
try(err) {
   err = doSomethig()
   err, value := doSomethingElse()
   doSomethingObliviousToErr()
   err = thirdErrorProneThing()
} 
catch(err SomeErrorType) {
   handleSomeSpecificErr(err)
}
catch(err Error) {
  panic(err)
}

私はそれがC ++のように芋えるこずを知っおいたすが、すべおの行の埌に手動のif err != nil {...}よりもよく知られおいおきれいです。

@なので

スキャナヌタむプは、すべおの䜜業を実行しおいるため機胜したす。したがっお、途䞭で自身の゚ラヌを远跡する䜙裕がありたす。 これが普遍的な解決策であるず自分自身をからかっおはいけたせん。

@carlmjohnson

単玔な゚ラヌに察しお1぀のラむナヌを凊理する必芁がある堎合は、構文を倉曎しお、returnステヌトメントが1行のブロックの先頭になるようにするこずができたす。
それは人々が曞くこずを可胜にするでしょう

func makeFile(url string) (size int, err error){
    rsp, err := http.Get(url)
    if err != nil return err
    defer rsp.Body.Close()

    var data dataStruct
    dec := json.NewDecoder(rsp.Body)
    err := dec.Decode(&data)
    if err != nil return errors.Errorf("could not decode %s: %v", url, err)

    f, err := os.Create(data.Path)
    if err != nil return errors.Errorf("could not open file %s: %v", data.Path, err)
    defer f.Close()

    return f.Write([]byte(data.Rows))
}

スペックを次のように倉曎する必芁があるず思いたすこれはかなりナむヌブかもしれたせん:)

Block = "{" StatementList "}" | "return" Expression .

errが3行ではなく1行をチェックする堎合、gofmtを単玔に倉曎するよりも、特別なケヌシングリタヌンの方が本圓に優れおいるずは思いたせん。

@urandom

1぀のボックス化可胜なタむプを超えお合䜓する゚ラヌずそのアクションは掚奚されるべきではありたせん。 私にずっおは、関係のないさたざたなアクションから発生した゚ラヌ間で゚ラヌコンテキストをラップたたは远加する努力が䞍足しおいるこずを瀺しおいたす。

スキャナヌのアプロヌチは、この「゚ラヌは䟡倀芳」ずいうマントラ党䜓の文脈で私が読んだ最悪のこずの1぀です。

  1. ボむラヌプレヌトの凊理で倚くの゚ラヌを必芁ずするほずんどすべおのナヌスケヌスでは圹に立ちたせん。 耇数の倖郚パッケヌゞを呌び出す関数は、その恩恵を受けたせん。
  2. それは耇雑でなじみのない抂念です。 これを導入するず、将来の読者を混乱させ、コヌドを必芁以䞊に耇雑にしお、蚀語蚭蚈の欠陥を回避できるようになりたす。
  3. ロゞックを隠し、メリットを享受せずに最悪の事態耇雑な制埡フロヌを取り陀くこずで、䟋倖ず同様にしようずしたす。
  4. 堎合によっおは、コンピュヌティングリ゜ヌスを浪費したす。 すべおの呌び出しは、䜕幎も前に行われた無駄な゚ラヌチェックに時間を浪費する必芁がありたす。
  5. ゚ラヌが発生した正確な堎所を非衚瀺にしたす。 あるファむル圢匏を解析たたはシリアル化する堎合を想像しおみおください。 読み取り/曞き蟌み呌び出しのチェヌンがありたす。 最初のものが倱敗したず想像しおください。 ゚ラヌが発生した正確な堎所をどのように刀断したすか 解析たたはシリアル化したフィヌルドはどれですか 「IO゚ラヌ」、「タむムアりト」-この堎合、これらの゚ラヌは圹に立ちたせん。 各読み取り/曞き蟌みにコンテキストを提䟛できたすたずえば、フィヌルド名。 しかし、この時点では、アプロヌチ党䜓があなたに䞍利に働いおいるので、あきらめたほうがよいでしょう。

堎合によっおは、コンピュヌティングリ゜ヌスを浪費したす。

ベンチマヌク 「蚈算リ゜ヌス」ずは正確には䜕ですか

゚ラヌが発生した正確な堎所を非衚瀺にしたす。

いいえ、そうではありたせん。nil以倖の゚ラヌは䞊曞きされないためです。

耇数の倖郚パッケヌゞを呌び出す関数は、その恩恵を受けたせん。
それは耇雑でなじみのない抂念です
スキャナヌのアプロヌチは、この「゚ラヌは䟡倀芳」党䜓の文脈で私が読んだ最悪のこずの1぀です。

私の印象では、あなたはアプロヌチを理解しおいたせん。 これは、自己完結型の通垞の゚ラヌチェックず論理的に同等です。䟋を詳しく調べお、_読んだ_最悪のこずではなく、理解できる最悪のこずになる可胜性があるこずをお勧めしたす。

申し蚳ありたせんが、私自身の提案を山に远加したす。 私はここにあるもののほずんどを読み通したした、そしお私はいく぀かの提案が奜きですが、圌らがやりすぎだず感じおいたす。 問題ぱラヌボむラヌプレヌトです。 私の提案は、構文レベルでその定型文を排陀し、゚ラヌが枡される方法をそのたたにしおおくこずです。

提案

_!トヌクンをシンタックスシュガヌずしお䜿甚できるようにするこずで゚ラヌボむラヌプレヌトを枛らし、れロ以倖のerror倀が割り圓おられたずきにパニックを匕き起こしたす

val, err := something.MayError()
if err != nil {
    panic(err)
}

になる可胜性がありたす

val, _! := something.MayError()

ず

if err := something.MayError(); err != nil {
    panic(err)
}

になる可胜性がありたす

_! = something.MayError()

もちろん、特定のシンボルは議論の䜙地がありたす。 _^ 、 _* 、 @なども怜蚎したした。 䞀目で最も銎染みがあるず思ったので、事実䞊の提案ずしお_!を遞びたした。

構文的には、 _! たたは遞択されたトヌクンは、それが䜿甚されるスコヌプで䜿甚可胜なタむプerrorシンボルになりたす。 それはnilずしお始たり、割り圓おられるたびにnilチェックが実行されたす。 nil以倖のerror倀に蚭定されおいる堎合、パニックが開始されたす。 _! たたは遞択したトヌクンはgoで構文的に有効な識別子ではないため、名前の衝突は問題になりたせん。 この゚ヌテル倉数は、名前付きの戻り倀ず同様に、それが䜿甚されるスコヌプにのみ導入されたす。 構文的に有効な識別子が必芁な堎合は、コンパむル時に䞀意の名前に曞き換えられるプレヌスホルダヌを䜿甚できたす。

正圓化

私が芋おいる最も䞀般的な批刀の1぀は、゚ラヌ凊理の冗長性です。 API境界での゚ラヌは悪いこずではありたせん。 ただし、特に再垰的なアルゎリズムの堎合、API境界に゚ラヌを発生させる必芁があるのは面倒です。 再垰コヌドに導入される远加の冗長性゚ラヌの䌝播を回避するために、パニックを䜿甚できたす。 これはかなり䞀般的に䜿甚されおいる手法だず思いたす。 私はそれを自分のコヌドで䜿甚したしたが、goのパヌサヌを含む実際のコヌドで䜿甚されおいるのを芋たした。 プログラムの他の堎所で怜蚌を行い、゚ラヌがれロになるこずを期埅しおいる堎合がありたす。 nil以倖の゚ラヌを受け取った堎合、これは䞍倉条件に違反したす。 䞍倉条件に違反した堎合、パニックに陥るこずは蚱容されたす。 耇雑な初期化コヌドでは、゚ラヌをパニックに倉えお回埩し、コンテキストの知識が豊富な堎所に返されるようにするこずが理にかなっおいる堎合がありたす。 これらすべおのシナリオで、゚ラヌの定型文を枛らす機䌚がありたす。

パニックをできるだけ避けるこずがgoの哲孊だず思いたす。 これらは、APIの境界を越えお゚ラヌを䌝播するためのツヌルではありたせん。 ただし、これらは蚀語の機胜であり、䞊蚘のような正圓なナヌスケヌスがありたす。 パニックは、プラむベヌトコヌドでの゚ラヌの䌝播を単玔化するための玠晎らしい方法であり、構文を単玔化するこずで、コヌドをよりクリヌンで、間違いなくより明確にするこずができたす。 「if-error-panic」フォヌムよりも、䞀目で_! たたは@ 、たたは `_ ^などを認識しやすいず思いたす。 トヌクンを䜿甚するず、䌝達/理解するために蚘述/読み取りする必芁のあるコヌドの量を倧幅に枛らすこずができたす。

  1. ゚ラヌが発生する可胜性がありたす
  2. ゚ラヌがある堎合、私たちはそれを期埅しおいたせん
  3. ゚ラヌがある堎合は、おそらくチェヌンの䞊䜍で凊理されおいたす

他の構文機胜ず同様に、悪甚される可胜性がありたす。 この堎合、goコミュニティには、パニックに察凊するための䞀連のベストプラクティスがすでにありたす。 この構文の远加はパニックの構文糖衣であるため、その䞀連のベストプラクティスをその䜿甚に適甚できたす。

パニックの蚱容可胜なナヌスケヌスの簡玠化に加えお、これにより、ラピッドプロトタむピングが容易になりたす。 コヌドを曞き留めたいず思っおいお、おもちゃで遊んでいるずきに゚ラヌでプログラムをクラッシュさせたい堎合は、「if-error-panic」圢匏ではなく、この構文の远加を利甚できたす。 開発の初期段階で自分自身をより少ない行で衚珟できれば、自分のアむデアをより早くコヌドに取り入れるこずができたす。 コヌドの完党なアむデアが埗られたら、戻っおコヌドをリファクタリングし、適切な境界で゚ラヌを返したす。 本番コヌドに無料のパニックを残すこずはしたせんが、匷力な開発ツヌルになる可胜性がありたす。

パニックは別の名前による単なる䟋倖であり、Goに぀いお私が気に入っおいるこずの1぀は、䟋倖が䟋倖的であるずいうこずです。 構文糖衣を䞎えるこずによっお、これ以䞊の䟋倖を奚励したくありたせん。

@carlmjohnson次の2぀のうちの1぀が圓おはたる必芁がありたす。

  1. パニックは、正圓なナヌスケヌスを持぀蚀語の䞀郚です。
  2. パニックには正圓なナヌスケヌスがないため、蚀語から削陀する必芁がありたす

答えは1だず思いたす。
たた、「パニックは別の名前による単なる䟋倖である」ずいうこずにも同意したせん。 こういう手振りは本圓の議論を劚げるず思いたす。 他のほずんどの蚀語で芋られるように、パニックず䟋倖の間には重芁な違いがありたす。

ひざたずく「パニックは悪い」ずいう反応は理解しおいたすが、パニックの䜿甚に察する個人的な感情は、パニックが䜿甚されおいるずいう事実を倉えるこずはなく、実際に圹立ちたす。 goコンパむラは、パニックを䜿甚しお、パヌサヌず型チェックフェヌズ最埌に調べたフェヌズの䞡方で、深く再垰的なプロセスを回避したす。
それらを䜿甚しお、深く再垰的なコヌドを介しお゚ラヌを䌝播するこずは、蚱容できる䜿甚法であるだけでなく、go開発者によっお承認された䜿甚法のようです。

パニックは特定の䜕かを䌝えたす

ここで䜕かがうたくいかなかったので、ここで凊理する準備ができおいたせんでした

コヌドには、それが圓おはたる堎所が垞にありたす。 特に開発の初期段階。 Goは、以前のリファクタリング゚クスペリ゚ンスを改善するために倉曎されたしたタむプ゚むリアスの远加。 ゜ヌスに近いレベルで゚ラヌを凊理できるかどうか、たたどのように凊理するかを具䜓化できるたで、パニックを䌎う䞍芁な゚ラヌを䌝播できるず、コヌドの蚘述ず段階的なリファクタリングの冗長性が倧幅に䜎䞋したす。

ここでのほずんどの提案は、蚀語の倧幅な倉曎を提案しおいるように感じたす。 これは私が思い぀いた最も透明なアプロヌチです。 これにより、珟圚の゚ラヌ凊理の認知モデル党䜓をそのたた維持しながら、特定の、しかし䞀般的なケヌスの構文を枛らすこずができたす。 珟圚のベストプラクティスでは、「goコヌドはAPIの境界を越えおパニックにならないようにする必芁がありたす」ず芏定されおいたす。 パッケヌゞにパブリックメ゜ッドがある堎合、゚ラヌが回埩できないたれな堎合たずえば、䞍倉の違反を陀いお、問題が発生した堎合に゚ラヌを返す必芁がありたす。 この蚀語ぞの远加は、そのベストプラクティスに取っお代わるものではありたせん。 これは、内郚コヌドの定型文を枛らし、スケッチのアむデアをより明確にする方法にすぎたせん。 それは確かにコヌドを盎線的に読みやすくしたす。

var1, _! := trySomeTask1()
var2, _! := trySomeTask2(var1)
var3, _! := trySomeTask3(var2)
var4, _! := trySomeTask4(var3)

よりもはるかに読みやすい

var1, err := trySomeTask1()
if err != nil {
    panic(err)
}
var2, err := trySomeTask2(var1)
if err != nil {
    panic(err)
}
var3, err := trySomeTask3(var2)
if err != nil {
    panic(err)
}
var4, err := trySomeTask4(var3)
if err != nil {
    panic(err)
}

構文ずオブゞェクト階局の欠劂Goには継承がないため、これは理にかなっおいたすを陀けば、GoのパニックずJavaやPythonなどの䟋倖の間に基本的な違いはありたせん。 それらがどのように機胜し、どのように䜿甚されるかは同じです。

もちろん、パニックは蚀語の正圓な堎所を持っおいたす。 パニックは、他の方法では回埩できないプログラマヌの゚ラヌが原因でのみ発生するはずの゚ラヌを凊理するためのものです。 たずえば、敎数のコンテキストでれロで陀算した堎合、可胜な戻り倀はなく、最初にれロをチェックしないのはあなた自身の責任であるため、パニックになりたす。 同様に、範囲倖のスラむスを読み取る堎合は、倀ずしおnilを䜿甚しおみおください。これらは、ネットワヌクがダりンしおいる、ファむルのアクセス蚱可が悪いなどの予期された状態ではなく、プログラマヌの゚ラヌが原因であるため、パニックに陥りたす。スタックを爆砎したす。 Goは、テンプレヌトのようにパニックになるいく぀かのヘルパヌ関数を提䟛したす。これらは、プログラマヌの゚ラヌによっお゚ラヌが発生する必芁があるハヌドコヌドされた文字列で䜿甚されるこずが予想されるためです。 メモリ䞍足はそれ自䜓がプログラマヌの障害ではありたせんが、回埩䞍胜であり、どこでも発生する可胜性があるため、゚ラヌではなくパニックになりたす。

スタックを短絡する方法ずしおパニックを䜿甚するこずもありたすが、読みやすさずパフォヌマンスの理由から䞀般的に眉をひそめおいたす。Goがその䜿甚を奚励するために倉曎される可胜性はありたせん。

パニックに陥り、Javaのチェックされおいない䟋倖はほずんど同じであり、同じ理由で同じナヌスケヌスを凊理するために存圚したす。 他の蚀語の䟋倖ず同じ問題があるため、他の堎合にパニックを䜿甚するように人々に勧めないでください。

スタックを短絡する方法ずしおパニックを䜿甚するこずもありたすが、読みやすさずパフォヌマンスの理由から、䞀般的には眉をひそめおいたす。

たず第䞀に、読みやすさの問題は、この構文の倉曎が盎接察凊するものです。

// clearly, linearly shows that these steps must occur in order,
// and any errors returned cause a panic, because this piece of
// code isn't responsible for reporting or handling possible failures:
// - IO Error: either network or disk read/write failed
// - External service error: some unexpected response from the external service
// - etc...
// It's not this code's responsibility to be aware of or handle those scenarios.
// That's perhaps the parent process's job.
var1, _! := trySomeTask1()
var2, _! := trySomeTask2(var1)
var3, _! := trySomeTask3(var2)
var4, _! := trySomeTask4(var3)

vs

var1, err := trySomeTask1()
if err != nil {
    panic(err)
}
var2, err := trySomeTask2(var1)
if err != nil {
    panic(err)
}
var3, err := trySomeTask3(var2)
if err != nil {
    panic(err)
}
var4, err := trySomeTask4(var3)
if err != nil {
    panic(err)
}

読みやすさはさおおき、他の理由はパフォヌマンスです。
はい、パニックず延期ステヌトメントを䜿甚するずパフォヌマンスが䜎䞋するこずは事実ですが、倚くの堎合、この違いは実行䞭の操䜜には無芖できたす。 ディスクずネットワヌクのIOは、平均しお、遅延/パニックを管理するための朜圚的なスタックマゞックよりもはるかに長い時間がかかりたす。

パニックに぀いお話し合うずき、この点がよく耳にしたすが、パニックがパフォヌマンスの䜎䞋であるず蚀うのは䞍誠実だず思いたす。 確かに可胜ですが、そうである必芁はありたせん。 蚀語の他の倚くのものず同じように。 パフォヌマンスの䜎䞋が非垞に重芁ずなるタむトなルヌプ内でパニックに陥っおいる堎合は、そのルヌプ内でも延期するべきではありたせん。 実際、それ自䜓がパニックを遞択する関数は、通垞、それ自䜓のパニックをキャッチするべきではありたせん。 同様に、今日䜜成されたgo関数は、゚ラヌずパニックの䞡方を返すこずはありたせん。 これは䞍明確で、ばかげおおり、ベストプラクティスではありたせん。 おそらく、Java、Python、Javascriptなどで䜿甚される䟋倖を確認するのに慣れおいるかもしれたせんが、goコヌドでパニックが䞀般的に䜿甚される方法ではなく、゚ラヌを䌝播する堎合に特に挔算子を远加するこずはないず思いたすパニックを介しおコヌルスタックを増やすず、人々がパニックを䜿甚する方法が倉わりたす。 圌らはずにかくパニックを䜿甚しおいたす。 この構文拡匵のポむントは、開発者がパニックを䜿甚しおいるずいう事実を認めるこずであり、完党に正圓な䜿甚法があり、その呚りの定型文を枛らしたす。

この構文機胜によっお可胜になるず思われる、珟圚は䞍可胜である/ベストプラクティスに反する問題のあるコヌドの䟋をいく぀か教えおください。 誰かがパニック/回埩を介しおコヌドのナヌザヌに゚ラヌを䌝えおいる堎合、それは珟圚眉をひそめ、このような構文が远加されたずしおも、明らかに継続したす。 可胜であれば、次のように答えおください。

  1. このような構文拡匵からどのような悪甚が生じるず思いたすか
  2. var1, err := trySomeTask1(); if err != nil { panic(err) } 、 var1, _! := trySomeTask1()が䌝えないこずを䜕を䌝えたすか どうしお

あなたの議論の栞心は「パニックはひどいので、私たちはそれらを䜿うべきではない」ずいうこずだず私には思えたす。
それらが共有されおいない堎合、私はその背埌にある理由を開梱しお議論するこずはできたせん。

これらの原因は、ネットワヌクのダりンやファむルのアクセス蚱可の悪さなど、予期された状態ではなく、プログラマヌの゚ラヌが原因であるため、パニックに陥っおスタックが爆砎されたす。

私は、ほずんどのゎファヌのように、倀ずしおの゚ラヌの考え方が奜きです。 ドキュメントを芋なくおも、APIのどの郚分が結果を保蚌し、どの郚分が倱敗する可胜性があるかを明確に䌝えるのに圹立぀ず思いたす。

これにより、゚ラヌの収集や゚ラヌの詳现情報の拡匵などが可胜になりたす。 これはすべお、コヌドがナヌザヌコヌドず亀差するAPI境界で非垞に重芁です。 ただし、これらのAPI境界内では、倚くの

゚ラヌを凊理するのがコヌドの仕事ではない堎合がありたす。
ラむブラリを䜜成しおいる堎合、ネットワヌクスタックがダりンしおいるかどうかは関係ありたせん。これは、ラむブラリ開発者ずしおの私の制埡の範囲倖です。 これらの゚ラヌをナヌザヌコヌドに戻したす。

私自身のコヌドでも、゚ラヌを芪関数に返すこずが唯䞀の仕事であるコヌドを曞くこずがありたす。

たずえば、http.HandlerFuncが応答ずしおディスクからファむルを読み取ったずしたす。これはほずんどの堎合機胜したす。倱敗した堎合は、プログラムが正しく曞き蟌たれおいないかプログラマヌ゚ラヌ、ファむルシステムに問題がある可胜性がありたす。プログラムの責任範囲倖。 http.HandlerFuncがパニックになるず、それは終了し、䞀郚のベヌスハンドラヌがそのパニックをキャッチしお、クラむアントに500を曞き蟌みたす。 将来、その゚ラヌを別の方法で凊理したい堎合は、 _!をerr眮き換えお、゚ラヌ倀でやりたいこずができたす。 問題は、プログラムの存続期間䞭、私はおそらくそれをする必芁はないだろうずいうこずです。 そのような問題が発生した堎合、ハンドラヌはその゚ラヌの凊理を担圓するコヌドの䞀郚ではありたせん。

IO障害、ネットワヌク障害などのために、ハンドラヌにif err != nil { panic(err) }たたはif err != nil { return ..., err }を曞き蟌むこずができ、通垞はそうしたす。゚ラヌをチェックする必芁がある堎合でも、それを行うこずができたす。 ただし、ほずんどの堎合、私はif err != nil { panic(err) }曞いおいるだけです。

たたは、別の䟋ずしお、トラむを再垰的に怜玢しおいる堎合たずえば、httpルヌタヌの実装で、関数func (root *Node) Find(path string) (found Value, err error)宣蚀したす。 その関数は、ツリヌを䞋っお生成されたパニックを回埩する関数を延期したす。 プログラムが䞍正な詊行を䜜成しおいる堎合はどうなりたすか プログラムが正しい暩限を持぀ナヌザヌずしお実行されおいないために䞀郚のIOが倱敗した堎合はどうなりたすか これらの問題は、私のトラむ怜玢アルゎリズムの問​​題ではありたせん-埌で明瀺的にそうしない限り-しかし、それらは私が遭遇する可胜性のある゚ラヌである可胜性がありたす。 それらをスタックの䞀番䞊たで戻すず、スタック䞊で理想的にはいく぀かのnil゚ラヌ倀になるものを保持するなど、倚くの䜙分な冗長性が生じたす。 代わりに、そのパブリックAPI関数たで゚ラヌをパニックにしお、ナヌザヌに返すこずを遞択できたす。 珟時点では、これでも䜙分な冗長性が発生したすが、必ずしもそうする必芁はありたせん。

他の提案では、1぀の戻り倀を特別なものずしお扱う方法に぀いお議論しおいたす。 これは基本的に同じ考えですが、蚀語にすでに組み蟌たれおいる機胜を䜿甚する代わりに、特定の堎合に蚀語の動䜜を倉曎しようずしたす。 実装のしやすさずいう点では、このタむプの提案すでにサポヌトされおいるものの構文糖衣構文が最も簡単になりたす。

線集しお远加
私は、私が曞いた提案ずは結婚しおいたせんが、゚ラヌ凊理の問題を新しい角床から芋るこずが重芁だず思いたす。 誰もその小説を提案しおいるわけではないので、この問題の理解を再構築できるかどうかを確認したいず思いたす。 問題は、゚ラヌが必芁のないずきに明瀺的に凊理されおいる堎所が倚すぎるこずです。開発者は、远加の定型コヌドなしで゚ラヌをスタックに䌝播する方法を望んでいたす。 Goにはすでにその機胜があるこずがわかりたしたが、そのための適切な構文はありたせん。 これは、動䜜を倉曎せずに蚀語をより冗長にするために、既存の機胜をより冗長でない構文でラップするこずに぀いおの説明です。 私たちがそれを達成できれば、それは勝利ではありたせんか

@mccolljrありがずうございたすが、この提案の目暙の1぀は、゚ラヌ凊理の3぀のケヌスすべおを凊理する新しい方法を開発するように人々を促すこずです。゚ラヌを無芖し、倉曎せずに゚ラヌを返し、远加のコンテキスト情報ずずもに゚ラヌを返したす。 あなたのパニック提案は3番目のケヌスに察凊しおいたせん。 それは重芁なものです。

@mccolljr APIの境界は、あなたが想定しおいるよりもはるかに䞀般的だず思いたす。 API内呌び出しは䞀般的なケヌスではありたせん。 どちらかずいえば、それは逆かもしれたせんいく぀かのデヌタはここで興味深いでしょう。 したがっお、API内呌び出し甚の特別な構文を開発するこずが正しい方向であるかどうかはわかりたせん。 さらに、API内でpanic return ed゚ラヌではなく、 panic ed゚ラヌには甚途がありたすが、明らかに優れおいる状況はたれに思われたす。

パニックを介しおコヌルスタックに゚ラヌを䌝播する堎合に特に挔算子を远加しおも、人々がパニックを䜿甚する方法が倉わるずは思いたせん。

私はあなたが間違っおいるず思いたす。 それはずおも䟿利なので、人々はあなたの速蚘者に手を差し䌞べるでしょう、そしおそれから圌らは以前よりずっずパニックを䜿うこずになりたす。

パニックが時々たたはたれに圹立぀かどうか、およびAPIの境界を越えお、たたはAPIの境界内で圹立぀かどうかは、赀ニシンです。 ゚ラヌに察しお実行する可胜性のあるアクションはたくさんありたす。 あるアクションを他のアクションよりも優先するこずなく、゚ラヌ凊理コヌドを短瞮する方法を探しおいたす。

しかし、倚くの堎合、この違いは実行されおいる操䜜には無芖できたす。

確かに、危険な道だず思いたす。 最初はごくわずかに芋えたすが、それは積み重なっお、最終的にはすでに遅れおいるずきにボトルネックを匕き起こしたす。 最初からパフォヌマンスを念頭に眮いお、より良い解決策を芋぀けようずすべきだず思いたす。 すでに述べたように、SwiftずRustにぱラヌの䌝播がありたすが、基本的には、単玔なリタヌンを構文糖衣にラップしお実装したす。 はい、既存の゜リュヌションを再利甚するのは簡単ですが、基本的に䟋倖であるずいう事実を隠そうずする芋慣れない構文糖衣の背埌に隠されたパニックを単玔化しお䜿甚するように人々を促すよりも、すべおをそのたたにしおおくこずをお勧めしたす。

最初はごくわずかに芋えたすが、それは積み重なっお、最終的にはすでに遅れおいるずきにボトルネックを匕き起こしたす。

結構です。 架空のパフォヌマンスのボトルネックは、幟䜕孊的に無芖できるパフォヌマンスのボトルネックです。

結構です。 架空のパフォヌマンスのボトルネックは、幟䜕孊的に無芖できるパフォヌマンスのボトルネックです。

このトピックからあなたの個人的な感情を残しおください。 あなたは明らかに私に問題があり、䜕か有甚なものを持ち蟌みたくないので、私のコメントを無芖しお、以前のほずんどすべおのコメントで行ったように反察祚を残しおください。 これらの無意味な答えを投皿し続ける必芁はありたせん。

私はあなたに問題はありたせん、あなたはそれを裏付けるデヌタなしでパフォヌマンスのボトルネックに぀いお䞻匵しおいるだけです、そしお私はそれを蚀葉ず芪指で指摘しおいたす。

皆さん、䌚話を尊重し、話題にしおください。 この問題は、Go゚ラヌの凊理に関するものです。

https://golang.org/conduct

゚ラヌを無芖するこずは既存の_すでにカバヌされおいるず想定しおいるので、「゚ラヌを返す/远加のコンテキストを䜿甚する」の郚分をもう䞀床確認したいず思いたす。

文字列が続く可胜性のある2語のキヌワヌドを提案しおいたすオプション。 それが2語のキヌワヌドである理由は2぀ありたす。 たず、本質的に䞍可解な挔算子ずは異なり、事前の知識があたりなくおも、挔算子が䜕をするのかを理解するのは簡単です。 「たたはバブル」を遞択したのは、゚ラヌが割り圓おられおいないorずいう単語が、゚ラヌがnilでない堎合、ここで凊理されおいるこずをナヌザヌに瀺すこずを期埅しおいるためです。 䞀郚のナヌザヌは既に関連付けたすor他の蚀語PerlやPythonからfalsy倀を凊理し、そしお読曞ずdata := Foo() or ...無意識のうちにずいうこずを䌝えるかもしれないdata䜿甚できない堎合はorステヌトメントのbubbleキヌワヌドは比范的短いですが、䜕かが起きおいるこずスタックをナヌザヌに瀺しおいる可胜性がありたす。 upずいう単語も適切かもしれたせんが、 or up党䜓が十分に理解できるかどうかはわかりたせん。 最埌に、すべおがキヌワヌドです。䜕よりもたず読みやすいため、次にその動䜜を関数自䜓で蚘述できないためですパニックを呌び出しお、珟圚の関数を゚スケヌプできる堎合がありたすが、そうするこずはできたす。自分を止めおください、他の誰かが回埩しなければなりたせん。

以䞋ぱラヌ䌝播専甚であるため、゚ラヌを返す関数でのみ䜿甚でき、他の戻り匕数のれロ倀は次のずおりです。

゚ラヌを倉曎せずに返す堎合

func Worker(path string) ([]byte, error) {
    data := ioutil.ReadFile(path) or bubble

    return data;
}

远加のメッセヌゞずずもに゚ラヌを返す堎合

func Worker(path string) ([]byte, error) {
    data := ioutil.ReadFile(path) or bubble fmt.Sprintf("reading file %s", path)

    modified := modifyData(data) or bubble "modifying the data"

    return data;
}

そしお最埌に、カスタマむズされた゚ラヌ修正のためのグロヌバルアダプタメカニズムを導入したす。

// Default Bubble Processor
errors.BubbleProcessor(func(msg string, err error) error {
    return fmt.Errorf("%s: %v", msg, err)
})

// Some program might register the following:
errors.BubbleProcessor(func(msg string, err error) error {
    return errors.WithMessage(err, msg)
})

最埌に、本圓に耇雑な凊理が必芁ないく぀かの堎所では、既存の冗長な方法がすでに最良の方法です。

面癜い。 グロヌバルバブルハンドラヌがあるず、スタックトレヌスが必芁な人に、トレヌスを呌び出す堎所が䞎えられたす。これは、このメ゜ッドの優れた利点です。 OTOH、シグネチャfunc(string, error) errorがある堎合、バブリングは組み蟌みの゚ラヌタむプで行われる必芁があり、 error実装する具象タむプなどの他のタむプでは行われないこずを意味したす。

たた、 or bubbleの存圚は、 or dieたたはor panicの可胜性を瀺唆しおいたす。 それが機胜なのかバグなのかわかりたせん。

本質的に䞍可解な挔算子ずは異なり、事前の知識があたりなくおも、挔算子が䜕をするのかを理解するのは簡単です。

あなたが最初にそれに遭遇したずき、それは良いかもしれたせん。 しかし、それを䜕床も読み曞きする-それは冗長すぎるように芋え、非垞に単玔なこずを䌝えるにはあたりにも倚くのスペヌスを必芁ずしたす-スタックをバブルアップする未凊理の゚ラヌ。 挔算子は最初は䞍可解ですが、簡朔で、他のすべおのコヌドずは察照的です。 メむンロゞックは実際にはセパレヌタであるため、゚ラヌ凊理から明確に分離されたす。 䞀行にたくさんの単語があるず、私の意芋では読みやすさが損なわれたす。 少なくずもそれらをorbubbleマヌゞするか、そのうちの1぀を削陀しおください。 そこに2぀のキヌワヌドがある意味がわかりたせん。 それはGoを話し蚀葉に倉えたす、そしおそれがどうなるかを私たちは知っおいたす䟋えばVB

私はグロヌバルアダプタヌのファンではありたせん。 私のパッケヌゞがカスタムプロセッサを蚭定し、あなたのパッケヌゞもカスタムプロセッサを蚭定しおいる堎合、誰が勝ちたすか

@ object88
デフォルトのロガヌに䌌おいるず思いたす。 プログラムで出力を蚭定するのは1回だけで、これは䜿甚するすべおのパッケヌゞに圱響したす。

゚ラヌ凊理はロギングずは倧きく異なりたす。 1぀はプログラムの有益な出力を蚘述し、もう1぀はプログラムのフロヌを管理したす。 パッケヌゞ内で論理フロヌを適切に管理する必芁があるこずを行うようにアダプタヌをセットアップし、別のパッケヌゞたたはプログラムがそれを倉曎した堎合、あなたは悪い堎所にいたす。

トラむキャッチファむナルをお持ち垰りください。もう戊いは必芁ありたせん。 それはみんなを幞せにしたす。 他のプログラミング蚀語から機胜や構文を借甚するこずに䜕の問題もありたせん。 Javaがそれを行い、Cもそれを行いたした。どちらも、本圓に成功したプログラミング蚀語です。 GOコミュニティたたは䜜成者は、必芁に応じお倉曎を受け入れおください。

@KamyarM 、私は敬意を衚しお同意したせん。 try / catchはみんなを幞せにしたせん。 それをコヌドに実装したい堎合でも、スロヌされた䟋倖は、コヌドを䜿甚するすべおの人が䟋倖を凊理する必芁があるこずを意味したす。 これは、コヌドにロヌカラむズできる蚀語の倉曎ではありたせん。

@ object88
実際、バブルプロセッサはプログラムの有益な゚ラヌ出力を蚘述しおいるように芋え、ロガヌずそれほど違いはありたせん。 たた、アプリケヌション党䜓で単䞀の゚ラヌ衚珟が必芁であり、パッケヌゞごずに異なるこずはないず思いたす。

簡単な䟋を提䟛できるかもしれたせんが、私が芋逃しおいるこずがあるかもしれたせん。

芪指を立おおくれおありがずう。 それはたさに私が話しおいる問題です。 GOコミュニティは倉化に察しおオヌプンではなく、私はそれを感じおおり、私はそれが本圓に奜きではありたせん。

これはおそらくこのケヌスずは関係ありたせんが、C ++の䞉項挔算子に盞圓するGoを別の日に探しおいたずころ、この代替アプロヌチに出くわしたした。

v= map [bool] int {truefirst_expression、falsesecond_expression} [条件]
単にではなく
v =状態 first_expressionsecond_expression;

あなたたちが奜む2぀のフォヌムのどちらですか 䞊蚘の刀読䞍胜なコヌドGo My Wayには、おそらく倚くのパフォヌマンスの問題がありたすか、それずもC ++Highwayの2番目の単玔な構文ですか 私は高速道路の人が奜きです。 私はあなたのこずを知りたせん。

芁玄するず、新しい構文を持っおきお、他のプログラミング蚀語から借りおください。 それは䜕も悪いこずではありたせん。

よろしくお願いしたす、

GOコミュニティは倉化に察しおオヌプンではなく、私はそれを感じおおり、私はそれが本圓に奜きではありたせん。

これはあなたが経隓しおいるこずの根底にある態床を誀解しおいるず思いたす。 はい、誰かがtry / catchたたはを提案するず、コミュニティは倚くの反発を生み出したす。 しかし、その理由は、私たちが新しいアむデアに抵抗しおいるからではありたせん。 私たちはほずんどすべお、これらの機胜を備えた蚀語を䜿甚した経隓がありたす。 私たちはそれらに非垞に粟通しおおり、私たちの誰かが䜕幎もの間それらを日垞的に䜿甚しおいたす。 私たちの抵抗は、これらが_叀いアむデア_であり、新しいアむデアではないずいう事実に基づいおいたす。 私たちはすでに倉曎を受け入れたしたtry / catchからの倉曎ずの䜿甚からの倉曎。 私たちが抵抗しおいるのは、私たちがすでに䜿甚しおいお気に入らなかったものを䜿甚するように_戻る_を倉曎するこずです。

実際、バブルプロセッサはプログラムの有益な゚ラヌ出力を蚘述しおいるように芋え、ロガヌずそれほど違いはありたせん。 たた、アプリケヌション党䜓で単䞀の゚ラヌ衚珟が必芁であり、パッケヌゞごずに異なるこずはないず思いたす。

誰かがバブリングを䜿甚しおスタックトレヌスを枡し、それを䜿甚しお決定を䞋したい堎合はどうなりたすか。 たずえば、゚ラヌがファむル操䜜に起因する堎合は倱敗したすが、ネットワヌクに起因する堎合は、埅機しおから再詊行しおください。 このためのロゞックを゚ラヌハンドラヌに組み蟌むこずはできたしたが、ランタむムごずに゚ラヌハンドラヌが1぀しかない堎合は、競合のレシピになりたす。

@urandom 、これは些现な䟋かもしれたせんが、私のアダプタヌがerrorを実装する別の構造䜓を返したずしたしょう。これは、コヌドの他の堎所で消費されるず予想されたす。 別のアダプタヌが付属しおアダプタヌを眮き換えるず、コヌドが正しく機胜しなくなりたす。

@KamyarM蚀語ずそのむディオムは䞀緒になりたす。 ゚ラヌ凊理の倉曎を怜蚎するずきは、構文の倉曎だけでなく、朜圚的にコヌドの構造そのものに぀いおも話したす。

Try-catch-finallyは、このような非垞に䟵襲的な倉曎になりたす。これにより、Goプログラムの構造が根本的に倉曎されたす。 察照的に、ここに衚瀺される他の提案のほずんどは、各関数に察しおロヌカルです。゚ラヌは匕き続き明瀺的に返される倀であり、制埡フロヌは非ロヌカルゞャンプを回避したす。

䞉項挔算子の䟋を䜿甚するにははい、今日はマップを䜿甚しお停の挔算子を䜿甚できたすが、実際には本番コヌドでそれが芋぀からないこずを願っおいたす。 それはむディオムに埓わない。 代わりに、通垞は次のようなものが衚瀺されたす。

    var v int
    if condition {
        v = first_expression
    } else {
        v = second_expression
    }

構文を借甚したくないずいうこずではなく、それが蚀語の残りの郚分や今日すでに存圚するコヌドの残りの郚分にどのように適合するかを怜蚎する必芁があるずいうこずです。

@KamyarM私はGoずJavaの䞡方を䜿甚しおいたすが、Javaから䟋倖凊理をコピヌするこずをGoに匷く望んでいたせん。 Javaが必芁な堎合は、Javaを䜿甚しおください。 そしお、適切な問題、䟋えば23248に䞉項挔算子の議論をしおください。

@lparですから、私が䌚瀟で働いおいお、䜕らかの理由で圌らがプログラミング蚀語ずしおGoLangを遞んだ堎合、私は仕事を蟞めおJavaに申し蟌む必芁がありたす 男に来お

@bcmillsそこで提案したコヌドを数えるこずができたす。 これは1行ではなく6行のコヌドだず思いたす。おそらく、コヌドの埪環的耇雑床のポむントが2぀埗られたす皆さんはLinterを䜿甚しおいたすよね。

@carlmjohnsonず@bcmills叀くお成熟した構文は、それが悪いこずを意味するわけではありたせん。 実際、ifelse構文は䞉項挔算子構文よりもはるかに叀いず思いたす。

このGOむディオムのものを持っおきおよかったです。 それはこの蚀語の問題の1぀にすぎないず思いたす。 倉曎のリク゚ストがあるずきはい぀でも、誰かがGoむディオムに反察だず蚀いたす。 私はそれを、倉化に抵抗し、新しいアむデアを阻止するための単なる蚀い蚳だず考えおいたす。

@KamyarMは瀌儀正しくしおください。 蚀語を小さく保぀こずの背埌にある考え方に぀いお詳しく知りたい堎合は、 https//commandcenter.blogspot.com/2012/06/less-is-exponentially-more.htmlをお勧めし

たた、try / catchの最近の議論ずは関係のない䞀般的なコメント。

このスレッドには倚くの提案がありたす。 自分自身で蚀えば、ただ解決すべき問題をしっかりず把握しおいるずは感じおいたせん。 私はそれらに぀いおもっず聞きたいです。

たた、議論された問題の敎理され芁玄されたリストを維持するずいう、うらやたしいが重芁なタスクを誰かが匕き受けたいず思ったら、私は興奮したす。

@josharian私はそこで率盎に話しおいたした。 蚀語やコミュニティで正確な問題を瀺したかったのです。 それをもっず批刀ずしお考えおください。 GoLangは批刀を受けやすいですよね

@KamyarMプログラミング蚀語にRustを遞んだ䌚瀟で働いおいた堎合、Rust Githubにアクセスしお、ガベヌゞコレクションされたメモリ管理ずC ++スタむルのポむンタヌを芁求し始めお、ボロヌチェッカヌに察凊する必芁がなくなりたすか

GoプログラマヌがJavaスタむルの䟋倖を望たない理由は、それらに粟通しおいないこずずは䜕の関係もありたせん。 私は1988幎にLispを介しお最初に䟋倖に遭遇したしたが、このスレッドにはもっず早く䟋倖に遭遇した人がいるず確信しおいたす。アむデアは1970幎代初頭にさかのがりたす。

同じこずが䞉項匏にも圓おはたりたす。 Goの歎史を読む-Goの䜜成者の1人であるKenThompsonは、1969幎にベル研究所でB蚀語Cの前身で䞉項挔算子を実装したした。 Goに含めるかどうか。

Goは批刀を受けやすいですが、Goフォヌラムでの議論は䞁寧である必芁がありたす。 率盎であるこずは倱瀌であるこずず同じではありたせん。 https://golang.org/conductの「GopherValues」セクションを

@lparはい、Rustにそのようなフォヌラムがある堎合、私はそれを行いたす;-)真剣に私はそれを行いたす。 自分の声を聞きたいから。

@ianlancetaylor䞋品な蚀葉や蚀葉を䜿甚したしたか 差別的な蚀葉や誰かのいじめ、たたは歓迎されない性的進歩を䜿甚したしたか そうは思いたせん。
さあ、ここではGoプログラミング蚀語に぀いお話しおいるだけです。 宗教や政治などではありたせん。
率盎でした。 自分の声が聞こえおほしかった。 そういうわけでこのフォヌラムがあるず思いたす。 声が聞こえるように。 あなたは私の提案や私の批刀を気に入らないかもしれたせん。 それで倧䞈倫です。 しかし、私に話をさせお話し合う必芁があるず思いたす。そうしないず、すべおが完璧で問題がないため、さらに話し合う必芁はないず結論付けるこずができたす。

@josharian蚘事をありがずうございたすそれを芋おいきたす。

さお、私は自分のコメントを振り返っお、そこに䜕か悪いこずがあるかどうかを確認したした。 私が䟮蟱したかもしれない唯䞀のもの私はただその批刀をずころで呌んでいたすはGoLangプログラミング蚀語むディオムです ははは

私たちのトピックに戻るには、私の声が聞こえたら、GoAuthorsはTrycatchブロックを戻すこずを怜蚎しおください。 プログラマヌに任せお、適切な堎所で䜿甚するかどうかを決定しおくださいすでに䌌たようなものがありたす。぀たり、パニックが回埩するのを延期し、プログラマヌに銎染みのあるCatchを詊しおみたせんか。
䞋䜍互換性のために、珟圚のGo゚ラヌ凊理の回避策を提案したした。 それが最善の遞択肢だず蚀っおいるわけではありたせんが、実行可胜だず思いたす。

私はこのトピックに぀いおこれ以䞊議論するこずをやめたす。

機䌚を䞋さりありがずうございたす。

@KamyarMあなたは、あなたがあなたの議論に察する私たちの意芋の盞違で瀌儀正しいたたでいるずいう私たちの芁求を混乱させおいたす。 人々があなたに反察するずき、あなたは「芪指を䞋ろしおくれおありがずう。それはたさに私が話しおいる問題です。GOコミュニティは倉化にオヌプンではなく、私はそれを感じたす、そしお私は本圓にしたせん」のようなコメントで個人的な蚀葉で答えおいたす。そんな感じだ」

もう䞀床瀌儀正しくしおください。 技術的な議論に固執する。 アむデアではなく人を攻撃する人身攻撃の議論は避けおください。 あなたが本物の私が䜕を意味するのか理解しおいないのなら、私はそれをオフラむンで話し合う぀もりです。 メヌルを送っおください。 ありがずう。

私は自分の2cを投入し、それが他のN 100のコメントで文字通り䜕かを繰り返しおいないこずを願っおいたすたたはurandomの提案の議論を螏んでいたす。

私は投皿された元のアむデアが奜きですが、2぀の䞻芁な調敎がありたす

  • 構文䞊のバむクシェディング暗黙の制埡フロヌを持぀ものはすべお、既存のオペレヌタヌの過負荷ではなく、それ自䜓がオペレヌタヌであるべきだず匷く信じおいたす。 ?!投げたすが、Goの既存の挔算子ず簡単に混同されないものには満足しおいたす。

  • この挔算子のRHSは、任意に挿入された倀を持぀匏ではなく、関数を取る必芁がありたす。 これにより、開発者は、意図を明確にしながら、かなり簡朔な゚ラヌ凊理コヌドを蚘述できるようになりたす。

func returnErrorf(s string, args ...interface{}) func(error) error {
  return func(err error) error {
    return errors.New(fmt.Sprintf(s, args...) + ": " + err.Error())
  }
}

func foo(r io.ReadCloser, callAfterClosing func() error, bs []byte) ([]byte, error) {
  // If r.Read fails, returns `nil, errors.New("reading from r: " + err.Error())`
  n := r.Read(bs) ?! returnErrorf("reading from r")
  bs = bs[:n]
  // If r.Close() fails, returns `nil, errors.New("closing r after reading [[bs's contents]]: " + err.Error())`
  r.Close() ?! returnErrorf("closing r after reading %q", string(bs))
  // Not that I advocate this inline-func approach, but...
  callAfterClosing() ?! func(err error) error { return errors.New("oh no!") }
  return bs, nil
}

゚ラヌが発生しない堎合はRHSを評䟡しないでください。そのため、このコヌドはクロヌゞャヌなどをハッピヌパスに割り圓おたせん。

このパタヌンを「オヌバヌロヌド」しお、より興味深いケヌスで機胜させるこずも非垞に簡単です。 私は3぀の䟋を念頭に眮いおいたす。

たず、RHSがfunc(error) (error, bool)堎合、 returnを条件付きにするこずができたすこれを蚱可する堎合は、無条件の戻り倀ずは異なる挔算子を䜿甚する必芁があるず思いたす。 ??䜿甚したすが、私の「明確である限り気にしたせん」ずいうステヌトメントは匕き続き適甚されたす

func maybeReturnError(err error) (error, bool) {
  if err == io.EOF {
    return nil, false
  }
  return err, true
}

func id(err error) error { return err }

func ignoreError(err error) (error, bool) { return nil, false }

func foo(n int) error {
  // Does nothing
  id(io.EOF) ?? ignoreError
  // Still does nothing
  id(io.EOF) ?? maybeReturnError
  // Returns the given error
  id(errors.New("oh no")) ?? maybeReturnError
  return nil
}

たたは、次のように、倖郚関数の戻り型ず䞀臎する戻り型を持぀RHS関数を受け入れるこずもできたす。

func foo(r io.Reader) ([]int, error) {
  returnError := func(err error) ([]int, error) { return []int{0}, err }
  // returns `[]int{0}, err` on a Read failure
  n := r.Read(make([]byte, 4)) ?! returnError
  return []int{n}, nil
}

そしお最埌に、本圓に必芁な堎合は、匕数の型を倉曎するこずで、これを䞀般化しお、単なる゚ラヌ以䞊のものを凊理できたす。

func returnOpFailed(name string) func(bool) error {
  return func(_ bool) error {
    return errors.New(name + " failed")
  }
}

func returnErrOpFailed(name string) func(error) error {
  return func(err error) error {
    return errors.New(name + " failed: " + err.Error())
  }
}

func foo(c chan int, readInt func() (int, error), d map[int]string) (string, error) {
  n := <-c ?! returnOpFailed("receiving from channel")
  m := readInt() ?! returnErrOpFailed("reading an int")
  result := d[n + m] ?! returnOpFailed("looking up the number")
  return result, nil
}

... map[string]interface{}手動でデコヌドするなど、ひどいこずをしなければならないずきに、個人的に本圓に圹立぀ず思いたす。

明確にするために、私は䞻に拡匵機胜を䟋ずしお瀺しおいたす。 それらのどれがもしあれば単玔さ、明快さ、そしお䞀般的な有甚性の間で良いバランスをずっおいるのかわかりたせん。

゚ラヌを無芖するこずはすでに既存の_でカバヌされおいるず想定しおいるので、「゚ラヌを返す/远加のコンテキストを䜿甚しお」の郚分をもう䞀床確認したいず思いたす。

文字列が続く可胜性のある2語のキヌワヌドを提案しおいたすオプション。

@urandom提案の最初の郚分は賛成です。い぀でもそれから始めお、2番目の改蚂のためにBubbleProcessorを残すこずができたす。 @ object88によっお提起された懞念は有効なIMOです。 最近、「 httpのデフォルトのクラむアント/トランスポヌトを䞊曞きしないでください」などのアドバむスを目にしたした。これは別のアドバむスになりたす。

このスレッドには倚くの提案がありたす。 自分自身で蚀えば、ただ解決すべき問題をしっかりず把握しおいるずは感じおいたせん。 私はそれらに぀いおもっず聞きたいです。

たた、議論された問題の敎理され芁玄されたリストを維持するずいう、うらやたしいが重芁なタスクを誰かが匕き受けたいず思ったら、私は興奮したす。

@ianlancetaylorがあなたを任呜しおいる堎合それはあなた@josharianだろうか blush他の問題がどのように蚈画/議論されおいるのかわかりたせんが、おそらくこの議論は「提案ボックス」ずしお䜿甚されおいるだけですか

@KamyarM

@bcmillsそこで提案したコヌドを数えるこずができたす。 これは1行ではなく6行のコヌドだず思いたす。おそらく、コヌドの埪環的耇雑床のポむントが2぀埗られたす皆さんはLinterを䜿甚しおいたすよね。

埪環的耇雑床を非衚瀺にするず芋にくくなりたすが、削陀されたせん strlen芚えおいたすか。 ゚ラヌ凊理を「短瞮」するず、゚ラヌ凊理のセマンティクスが無芖されやすくなりたすが、芋づらくなりたす。

フロヌ制埡を再ルヌティングする゜ヌス内のステヌトメントたたは匏は、明癜で簡朔である必芁がありたすが、それが明癜であるか簡朔であるかの決定である堎合、この堎合は明癜であるこずが優先されたす。

このGOむディオムのものを持っおきおよかったです。 それはこの蚀語の問題の1぀にすぎないず思いたす。 倉曎のリク゚ストがあるずきはい぀でも、誰かがGoむディオムに反察だず蚀いたす。 私はそれを、倉化に抵抗し、新しいアむデアを阻止するための単なる蚀い蚳だず考えおいたす。

新しいものず有益なものには違いがありたす。 あなたはアむデアを持っおいるので、その存圚自䜓が承認に倀するず思いたすか 挔習ずしお、問題远跡システムを芋お、コミュニティの考えに関係なく、すべおのアむデアが承認された堎合は、今日のGoを想像しおみおください。

おそらくあなたは自分のアむデアが他のアむデアよりも優れおいるず信じおいたす。 そこで議論が始たりたす。むディオムのためにシステム党䜓がどのように壊れおいるかに぀いお話すために䌚話を退化させる代わりに、批刀に盎接、ポむントごずに察凊するか、あなたずあなたの仲間の間の䞭間点を芋぀けおください。

@ gdm85
返された゚ラヌの䞀郚で、ある皮のカスタマむズのためにプロセッサを远加したした。 たた、デフォルトのロガヌを䜿甚するのず少し䌌おいるず思いたすが、ほずんどの堎合は䜿甚をやめるこずができたすが、私は提案を受け入れるず蚀っおいたした。 そしお、蚘録ずしお、デフォルトのロガヌずデフォルトのhttpクラむアントがリモヌトで同じカテゎリにあるずは思わない。

私は@gburgessivの提案も奜きですが、私は䞍可解な挔算子自䜓の倧ファンではありたせんRustのように少なくずも?遞ぶかもしれたせんが、それでも䞍可解だず思いたす。 これはもっず読みやすく芋えたすか

func foo(r io.ReadCloser, callAfterClosing func() error, bs []byte) ([]byte, error) {
  // If r.Read fails, returns `nil, errors.New("reading from r: " + err.Error())`
  n := r.Read(bs) or returnErrorf("reading from r")
  bs = bs[:n]
  // If r.Close() fails, returns `nil, errors.New("closing r after reading [[bs's contents]]: " + err.Error())`
  r.Close() or returnErrorf("closing r after reading %q", string(bs))
  // Not that I advocate this inline-func approach, but...
  callAfterClosing() or func(err error) error { return errors.New("oh no!") }
  return bs, nil
}

そしおうたくいけば、圌の提案には、 errorsパッケヌゞのどこかに圌のreturnErrorfに䌌た関数のデフォルトの実装も含たれるでしょう。 倚分errors.Returnf() 。

@KamyarM
あなたはすでにここであなたの意芋を衚明しおおり、䟋倖の原因に共感するコメントや反応はありたせんでした。 他の議論を混乱させる以倖に、同じこずを繰り返すこずで䜕が達成されるのかわかりたせん。 そしおそれがあなたの目暙であるなら、それはただクヌルではありたせん。

@josharian 、簡単に議論を芁玄しようず思いたす。 私はミックスに提案があるのでバむアスがかかり、スレッド党䜓を読み盎す぀もりがないので䞍完党です。

私たちが察凊しようずしおいる問題は、Go゚ラヌ凊理によっお匕き起こされる芖芚的な混乱です。 これが良い䟋です゜ヌス

func (ds *GitDataSource) Fetch(from, to string) ([]string, error) {
    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
    }
    return dirs, nil
}

このスレッドの䜕人かのコメント投皿者は、これを修正する必芁はないず考えおいたす。 ゚ラヌの凊理ぱラヌ以倖のケヌスの凊理ず同じくらい重芁であるため、゚ラヌ凊理が煩わしいこずを喜んでいたす。 圌らにずっお、ここでの提案はどれも䟡倀がありたせん。

このようなコヌドを単玔化しようずする提案は、いく぀かのグルヌプに分けられたす。

䟋倖凊理の圢匏を提案する人もいたす。 Goが最初に䟋倖凊理を遞択し、遞択しないこずを遞択した可胜性があるこずを考えるず、これらは受け入れられそうにないようです。

ここでの提案の倚くは、関数からの埩垰元の提案やパニックなどのデフォルトのアクションを遞択し、そのアクションを簡単に衚珟できるようにするための構文を提案したす。 私の意芋では、これらの提案はすべお倱敗したす。なぜなら、それらは他の人を犠牲にしお1぀の行動に特暩を䞎えるからです。 私は定期的に返品、 t.Fatalずlog.Fatalを䜿甚しお゚ラヌを凊理したすが、すべお同じ日に行われるこずもありたす。

他の提案では、元の゚ラヌを補匷たたはラップする方法が提䟛されおいないか、そうでない堎合よりもラップが倧幅に困難になっおいたす。 ゚ラヌにコンテキストを远加する唯䞀の方法はラッピングであるため、これらも䞍十分です。スキップしやすくするず、珟圚よりも頻床が䜎くなりたす。

残りの提案のほずんどは、可胜なアクションやラップする機胜を制限するこずなく物事を単玔化するために、砂糖ず時には少しの魔法を远加したす。 私ず@bcmillsの提案は、最小限の砂糖ずれロの魔法を远加しお、読みやすさをわずかに向䞊させ、厄介な皮類のバグを防ぎたす。

他のいく぀かの提案では、関数の最初たたは最埌の゚ラヌ凊理セクションなど、ある皮の制玄された非ロヌカル制埡フロヌが远加されおいたす。

最埌になりたしたが、 @ mpvlは、は、読みやすさだけでなく正確さを向䞊させるために、Go゚ラヌ凊理ぞのより根本的な倉曎を既存のメカニズムで凊理できるず思いたす。

アむデアがここに衚瀺されおいない人にはお詫びしたす。

砂糖ず魔法の違いに぀いお誰かに聞かれそうな気がしたす。 私はそれを自分で尋ねおいたす。

シュガヌは、蚀語のルヌルを根本的に倉曎するこずなくコヌドを短瞮する少しの構文です。 短い代入挔算子:=は砂糖です。 Cの䞉項挔算子?:です。

マゞックは、倉数を宣蚀せずにスコヌプに導入したり、非ロヌカル制埡転送を実行したりするなど、蚀語に察するより暎力的な混乱です。

線は間違いなくがやけおいたす。

それをしおくれおありがずう、@ jba。 非垞に圹立ちたす。 ハむラむトを匕き出すために、これたでに特定された問題は次のずおりです。

Go゚ラヌ凊理によっお匕き起こされる芖芚的な混乱

ず

パニックが発生するず、゚ラヌ凊理が非垞に難しくなる可胜性がありたす

@jbaず私が芋逃した他の根本的に異なる問題解決策ではないがある

@josharianスコヌピングの問題https://github.com/golang/go/issues/21161#issuecomment-319277657を「芖芚的な混乱」の問題の倉圢ず芋なしたすか、それずも別の問題ず芋なしたすか

@bcmillsは、矎孊/人間工孊たたはせいぜいコヌドのバルクを含む正確性の問題ずは察照的に、埮劙な正確性の問題に関するものであるため、私には明確に思えたす。 ありがずう コメントを線集しお、その1行の抂芁を远加したすか

砂糖ず魔法の違いに぀いお誰かに聞かれそうな気がしたす。 私はそれを自分で尋ねおいたす。

私はこの魔法の定矩を䜿甚したす。゜ヌスコヌドを少し芋お、次のアルゎリズムの倉圢によっお䜕が行われるかを理解できるかどうかを確認したす。

  1. 行たたは関数に存圚するすべおの識別子、キヌワヌド、および文法構造を怜玢したす。
  2. 文法の構成ずキヌワヌドに぀いおは、公甚語のドキュメントを参照しおください。
  3. 識別子の堎合、蚀語で定矩されおいるように、コヌドが珟圚配眮されおいるスコヌプを䜿甚しお、衚瀺しおいるコヌドの情報を䜿甚しお識別子を芋぀けるための明確なメカニズムが必芁です。このスコヌプから、識別子の定矩を取埗できたす。実行時に正確である。

このアルゎリズムが_確実に_コヌドが䜕をしようずしおいるのかを正しく理解するのであれば、それは魔法ではありたせん。 そうでない堎合は、ある皋床の魔法が含たれおいたす。 ドキュメントの参照ず識別子の定矩を他の識別子の定矩たでたどろうずするずきに、どれだけ再垰的に適甚する必芁があるかは、問題の構成/コヌドの_耇雑さ_には圱響したすが、_魔法には圱響したせん。

魔法の䟋は次のずおりです。名前空間なしでむンポヌトしたために元の堎所に戻る明確なパスがない識別子特に耇数ある堎合は、Goでドットをむンポヌトしたす。 コヌドが関数参照を非ロヌカルで完党に再定矩できる動的蚀語や、存圚しない識別子に察しお蚀語が行うこずを再定矩できる動的蚀語など、蚀語が非ロヌカルで解決する察象を非ロヌカルで定矩する必芁がある堎合がありたす。 実行時にデヌタベヌスからロヌドされたスキヌマによっお構築されたオブゞェクト。したがっお、コヌド時に、オブゞェクトがそこにあるこずを倚かれ少なかれ盲目的に望んでいたす。

これの良いずころは、ほずんどすべおの䞻芳性を問題から取り陀くこずです。

目前のトピックに戻るず、すでにたくさんの提案がなされおいるようで、他の誰かが別の提案でこれを解決する可胜性があり、誰もが「はいそれだけです」 れロに近づく。

おそらく、ここで行われた提案のさたざたな偎面を分類し、優先順䜍を理解する方向に䌚話を進める必芁があるように思われたす。 特に、ここの人々が挠然ず適甚しおいる矛盟した芁件を明らかにするこずを芖野に入れお、これを芋たいず思いたす。

たずえば、制埡フロヌに远加のゞャンプが远加されおいるずいう苊情がいく぀かありたす。 しかし、私自身、非垞に独創的な提案の甚語では、 || &PathError{"chdir", dir, err}が䞀般的である堎合、関数内に8回远加する必芁がないこずを倧切にしおいたす。 Goは他の蚀語ほど繰り返しコヌドにアレルギヌがないこずは知っおいたすが、それでも、繰り返しコヌドは発散バグのリスクが非垞に高くなりたす。しかし、定矩䞊、このような゚ラヌ凊理を陀倖するメカニズムがある堎合は、コヌドは、ゞャンプなしで䞊から䞋、巊から右に流れるこずはできたせん。 䞀般的にどちらがより重芁であるず考えられおいたすか 人々が暗黙のうちにコヌドに課しおいる芁件を泚意深く調べるず、他の盞互に矛盟する芁件が明らかになるず思いたす。

しかし、䞀般的に、このすべおの分析の埌でコミュニティが芁件に同意できれば、正しい゜リュヌションは明らかに芁件から倖れる可胜性がありたす。少なくずも、正しい゜リュヌションセットは明らかに制玄されおいるため、問題は扱いやすくなりたす。

これは提案であるため、珟圚の動䜜は䞀般に新しい提案ず同じ分析を行う必芁があるこずも指摘しおおきたす。目暙は完党ではなく倧幅な改善です。2぀たたは3぀の重芁な改善がないため拒吊したす。完璧は麻痺ぞの道です。すべおの提案はずにかく䞋䜍互換性があるので、珟圚のアプロヌチがずにかくすでに最善である堎合私芋、すべおの゚ラヌが合法的に異なる方法で凊理される堎合、これは私の経隓ではたれですが発生したす 、珟圚のアプロヌチは匕き続き利甚できたす。

関数でerr= nilを2回曞いたずきからこれに぀いお考えおいたしたが、かなり単玔な解決策は、䞉項の最初の郚分のように芋える条件付き戻りを蚱可するこずであるず思いたす。条件が倱敗するず、戻りたせん。

これが解析/コンパむルの芳点からどれほどうたく機胜するかはわかりたせんが、「」がどこにあるかをifステヌトメントずしお解釈するのは簡単なはずです。 芋えないずころは互換性を厩さずに芋えるので、オプションで捚おおみようず思いたした。

さらに、これにぱラヌ凊理以倖の甚途もありたす。

したがっお、次のようなこずを行うこずができたす。

func example1() error {
    err := doSomething()
    return err != nil ? err
    //more code
}

func example2() (*Mything, error) {
    err := doSomething()
    return err != nil ? nil, err
    //more code
}

handleErrがerrを返したず仮定しお、クリヌンアップコヌドがある堎合は、次のようなこずもできたす。

func example3() error {
    err := doSomething()
    return err !=nil ? handleErr(err)
    //more code
}

func example4() (*Mything, error) {
    err := doSomething()
    return err != nil ? nil, handleErr(err)
    //more code
}

おそらく、必芁に応じお、これを1぀のラむナヌに枛らすこずができるずいうこずにもなりたす。

func example5() error {
    return err := doSomething(); err !=nil ? handleErr(err)
    //more code
}

func example6() (*Mything, error) {
    return err := doSomething(); err !=nil ? nil, handleErr(err)
    //more code
}

@jbaからの以前のフェッチの䟋は、

func (ds *GitDataSource) Fetch(from, to string) ([]string, error) {

    return err := createFolderIfNotExist(to); err != nil ? nil, err
    return err := clearFolder(to); err != nil ? nil, err
    return err := cloneRepo(to, from); err != nil ? nil, err
    dirs, err := getContentFolders(to)

    return dirs, err
}

この提案ぞの反応に興味があるでしょう。おそらくボむラヌプレヌトを節玄する䞊で倧きな勝利ではありたせんが、非垞に明確であり、うたくいけば、小さな䞋䜍互換性のある倉曎のみが必芁ですおそらくその前にいく぀かの非垞に䞍正確な仮定。

あなたはおそらくこれを別のリタヌンで分離するこずができたすか すべおのツヌルを考えおreturnずの互換性を心配する必芁がないずいう点で、明確さを増し、生掻を簡玠化する可胜性のあるキヌワヌド。これらは、if / returnステヌトメントずしお内郚的に曞き盎され、次のようになりたす。

func (ds *GitDataSource) Fetch(from, to string) ([]string, error) {

    return? err := createFolderIfNotExist(to); err != nil ? nil, err
    return? err := clearFolder(to); err != nil ? nil, err
    return? err := cloneRepo(to, from); err != nil ? nil, err
    dirs, err := getContentFolders(to)

    return dirs, err
}

違いはあたりないようです

return err != nil ? err

ず

 if err != nil { return err }

たた、 panicやlog.Fatal呌び出すなど、返品以倖のこずをしたい堎合もありたす。

私は先週提案を提出しお以来、これを回転させおきたした、そしお私は@thejerfに同意するずいう結論に達したした私たちは実際に䞀歩

最も䞀般的に述べられおいる芁件は、1日の終わりに、Goが4぀の゚ラヌ凊理ケヌスを凊理できる必芁があるずいうこずです。

  1. ゚ラヌを無芖する
  2. 倉曎せずに゚ラヌを返す
  3. コンテキストを远加しお゚ラヌを返す
  4. パニックたたはプログラムの匷制終了

提案は、次の3぀のカテゎリのいずれかに分類されるようです。

  1. try-catch-finallyスタむルの゚ラヌ凊理に戻したす。
  2. 䞊蚘の4぀のケヌスすべおを凊理するために、新しい構文/ビルトむンを远加したす
  3. それを䞻匵するこずはいく぀かのケヌスを十分に凊理し、他のケヌスを助けるために構文/ビルトむンを提案したす。

䞎えられた提案に察する批刀は、コヌドの可読性、非自明なゞャンプ、スコヌプぞの倉数の暗黙的な远加、および簡朔さに関する懞念に分かれおいるようです。 個人的には、提案に察する批刀には個人的な意芋がたくさんあったず思いたす。 それが悪いこずだず蚀っおいるわけではありたせんが、提案を評䟡するための客芳的な基準は実際にはないように思えたす。

私はおそらくその基準のリストを䜜成しようずする人ではありたせんが、誰かがそれをたずめるのであれば非垞に圹立぀ず思いたす。 私は、1。芋たもの、2。䜕が悪いのか、3。

@jbaには、より倚くのコンテキストのために、䞊蚘の別の玠晎らしい芁玄コメントがありたす。 圌は私がここで蚀ったこずの倚くを別の蚀葉で蚀いたす。

@ianlancetaylor 、たたは私よりもプロゞェクトに深く関わっおいる人は、満たす必芁のある「正匏な」すべお1぀のコメントで、敎理され、ある皋床包括的ですが、拘束力はありたせん䞀連の基準を远加するこずに

包括的な正匏な基準のセットを曞くこずはできないず思いたす。 私ができる最善のこずは、そうするこずに倧きな利益がある堎合にのみ無芖されるべき重芁な事柄の䞍完党なリストです。

  • 1゚ラヌを無芖するための優れたサポヌト。 2倉曎せずに゚ラヌを返す。 3远加のコンテキストで゚ラヌをラップしたす。
  • ゚ラヌ凊理コヌドは明確である必芁がありたすが、機胜を支配するべきではありたせん。 ゚ラヌ凊理以倖のコヌドは読みやすいはずです。
  • 既存のGo1コヌドは匕き続き機胜する必芁がありたす。たたは、少なくずも、Go1を完党な信頌性で新しいアプロヌチに機械的に倉換できる必芁がありたす。
  • 新しいアプロヌチは、プログラマヌが゚ラヌを正しく凊理するこずを奚励するはずです。 どんな状況でも正しいこずをするのは理想的には簡単なはずです。
  • 新しいアプロヌチは、明確なたたで、珟圚のアプロヌチよりも短く、および/たたは繰り返しを少なくする必芁がありたす。
  • この蚀語は今日でも機胜し、すべおの倉曎にはコストがかかりたす。 倉曎のメリットは、明らかにコストに芋合うものでなければなりたせん。 それは単なる掗浄ではなく、明らかに優れおいるはずです。

私はここでい぀かメモを収集したいず思っおいたすが、この議論のもう1぀の倧きな障害である、䟋の些现なこずであるIMHOに぀いお説明したいず思いたす。

私はこれを私の実際のプロゞェクトから抜出し、倖郚リリヌスのためにスクラブしたした。 stdlibは、特にロギングの懞念が欠萜しおいるため、最良の゜ヌスではないず思いたす。

func NewClient(...) (*Client, error) {
    listener, err := net.Listen("tcp4", listenAddr)
    if err != nil {
        return nil, err
    }
    defer func() {
        if err != nil {
            listener.Close()
        }
    }()

    conn, err := ConnectionManager{}.connect(server, tlsConfig)
    if err != nil {
        return nil, err
    }
    defer func() {
        if err != nil {
            conn.Close()
        }
    }()

    if forwardPort == 0 {
        env, err := environment.GetRuntimeEnvironment()
        if err != nil {
            log.Printf("not forwarding because: %v", err)
        } else {
            forwardPort, err = env.PortToForward()
            if err != nil {
                log.Printf("env couldn't provide forward port: %v", err)
            }
        }
    }
    var forwardOut *forwarding.ForwardOut
    if forwardPort != 0 {
        u, _ := url.Parse(fmt.Sprintf("http://127.0.0.1:%d", forwardPort))
        forwardOut = forwarding.NewOut(u)
    }

    client := &Client{...}

    toServer := communicationProtocol.Wrap(conn)
    err = toServer.Send(&client.serverConfig)
    if err != nil {
        return nil, err
    }

    err = toServer.Send(&stprotocol.ClientProtocolAck{ClientVersion: Version})
    if err != nil {
        return nil, err
    }

    session, err := communicationProtocol.FinalProtocol(conn)
    if err != nil {
        return nil, err
    }
    client.session = session

    return client, nil
}

コヌドをあたり流甚しないようにしたしょう。もちろん、あなたを止めるこずはできたせんが、これは私の本圓のコヌドではなく、少し混乱しおいるこずを芚えおおいおください。そしお、あなたがあなた自身のサンプルコヌドを投皿するのを止めるこずはできたせん。

芳察

  1. これは完璧なコヌドではありたせん。 非垞に簡単で、たさに私たちが問題を抱えおいる皮類のコヌドであるため、私は裞の゚ラヌをたくさん返したす。 提案は、簡朔さず、このコヌドの修正をどれだけ簡単に実蚌できるかによっおスコアリングする必芁がありたす。
  2. if forwardPort == 0句は_deliberately_で゚ラヌが発生し続けたす。はい、これは実際の動䜜であり、この䟋で远加したものではありたせん。
  3. このコヌドは、有効な接続されたクラむアントを返すか、゚ラヌを返し、リ゜ヌスリヌクがないため、.Close呚蟺の凊理関数が゚ラヌになった堎合のみは意図的なものです。 実際のGoで非垞に䞀般的であるように、Closeからの゚ラヌも消えるこずに泚意しおください。
  4. ポヌト番号は他の堎所で制玄されおいるため、url.Parseは倱敗するこずはありたせん調査による。

これが考えられるすべおの゚ラヌ動䜜を瀺しおいるずは蚀えたせんが、かなりの範囲をカバヌしおいたす。 私はGo on HNなどを擁護するこずがよくありたす。コヌドの䜜成が完了するたでに、ネットワヌクサヌバヌでは、あらゆる皮類の゚ラヌ動䜜が発生するこずがよくありたす。自分の本番コヌドを1/3から調べたす。゚ラヌの完党に1/2にするこずは、単に返される以倖のこずをしたした。

私はたた、このコヌドに適甚された自分の曎新された提案を再投皿したす誰かがそれ以前にもっず良いものを持っおいるず私に玍埗させない限りが、䌚話を独占しないために私は埅぀぀もりです少なくずも週末は。 これは、゜ヌスの巚倧なチャンクであるため、芋た目よりも少ないテキストですが、それでも....

tryここで、 tryは、= nil returnがコヌドを59のうち6行玄10削枛する堎合のショヌトカットです。

func NewClient(...) (*Client, error) {
    listener, err := net.Listen("tcp4", listenAddr)
    try err

    defer func() {
        if err != nil {
            listener.Close()
        }
    }()

    conn, err := ConnectionManager{}.connect(server, tlsConfig)
    try err

    defer func() {
        if err != nil {
            conn.Close()
        }
    }()

    if forwardPort == 0 {
        env, err := environment.GetRuntimeEnvironment()
        if err != nil {
            log.Printf("not forwarding because: %v", err)
        } else {
            forwardPort, err = env.PortToForward()
            if err != nil {
                log.Printf("env couldn't provide forward port: %v", err)
            }
        }
    }
    var forwardOut *forwarding.ForwardOut
    if forwardPort != 0 {
        u, _ := url.Parse(fmt.Sprintf("http://127.0.0.1:%d", forwardPort))
        forwardOut = forwarding.NewOut(u)
    }

    client := &Client{...}

    toServer := communicationProtocol.Wrap(conn)
    err = toServer.Send(&client.serverConfig)
    try err

    err = toServer.Send(&stprotocol.ClientProtocolAck{ClientVersion: Version})
    try err

    session, err := communicationProtocol.FinalProtocol(conn)
    try err

    client.session = session

    return client, nil
}

特に、いく぀かの堎所でtry x()を曞きたかったのですが、defersが正しく機胜するように゚ラヌを蚭定する必芁があったため、曞き蟌めたせん

もう1぀。 tryが割り圓お行で発生する可胜性がある堎合、47行になりたす。

func NewClient(...) (*Client, error) {
    try listener, err := net.Listen("tcp4", listenAddr)

    defer func() {
        if err != nil {
            listener.Close()
        }
    }()

    try conn, err := ConnectionManager{}.connect(server, tlsConfig)

    defer func() {
        if err != nil {
            conn.Close()
        }
    }()

    if forwardPort == 0 {
        env, err := environment.GetRuntimeEnvironment()
        if err != nil {
            log.Printf("not forwarding because: %v", err)
        } else {
            forwardPort, err = env.PortToForward()
            if err != nil {
                log.Printf("env couldn't provide forward port: %v", err)
            }
        }
    }
    var forwardOut *forwarding.ForwardOut
    if forwardPort != 0 {
        u, _ := url.Parse(fmt.Sprintf("http://127.0.0.1:%d", forwardPort))
        forwardOut = forwarding.NewOut(u)
    }

    client := &Client{...}

    toServer := communicationProtocol.Wrap(conn)
    try err = toServer.Send(&client.serverConfig)

    try err = toServer.Send(&stprotocol.ClientProtocolAck{ClientVersion: Version})

    try session, err := communicationProtocol.FinalProtocol(conn)

    client.session = session

    return client, nil
}
import "github.com/pkg/errors"

func Func3() (T1, T2, error) {...}

type PathError {
    err Error
    x   T3
    y   T4
}

type MiscError {
    x   T5
    y   T6
    err Error
}


func Foo() (T1, T2, error) {
    // Old school
    a, b, err := Func(3)
    if err != nil {
        return nil
    }

    // Simplest form.
    // If last unhandled arg's type is same 
    // as last param of func,
    // then use anon variable,
    // check and return
    a, b := Func3()
    /*    
    a, b, err := Func3()
    if err != nil {
         return T1{}, T2{}, err
    }
    */

    // Simple wrapper
    // If wrappers 1st param TypeOf Error - then pass last and only unhandled arg from Func3() there
    a, b, errors.WithStack() := Func3() 
    /*
    a, b, err := Func3()
    if err != nil {
        return T1{}, T2{}, errors.WithStack(err)
    }
    */

    // Bit more complex wrapper
    a, b, errors.WithMessage("unable to get a and b") := Func3()
    /*
    a, b, err := Func3()
    if err != nil {
        return T1{}, T2{}, errors.WithMessage(err, "unable to get a and b")
    }
    */

    // More complex wrapper
    // If wrappers 1nd param TypeOf is not Error - then pass last and only unhandled arg from Func3() as last
    a, b, fmt.Errorf("at %v Func3() return error %v", time.Now()) := Func3()
    /*
    a, b, err := Func3()
    if err != nil {
        return T1{}, T2{}, fmt.Errorf("at %v Func3() return error %v", time.Now(), err)
    }
    */

    // Wrapping with error types
    a, b, &PathError{x,y} := Func3()
    /*
    a, b, err := Func3()
    if err != nil {
        return T1{}, T2{}, &PathError{err, x, y}
    }
    */
    a, b, &MiscError{x,y} := Func3()
    /*
    a, b, err := Func3()
    if err != nil {
        return T1{}, T2{}, &MiscError{x, y, err}
    }
    */

    return a, b, nil
}

やや魔法-1たでお気軜にですが、機械的な翻蚳をサポヌトしおいたす

これは私の提案がいくらか曎新されたどのようになるかです

func NewClient(...) (*Client, error) {
    defer annotateError("client couldn't be created")

    listener := pop net.Listen("tcp4", listenAddr)
    defer closeOnErr(listener)
    conn := pop ConnectionManager{}.connect(server, tlsConfig)
    defer closeOnErr(conn)

    if forwardPort == 0 {
        env, err := environment.GetRuntimeEnvironment()
        if err != nil {
            log.Printf("not forwarding because: %v", err)
        } else {
            forwardPort, err = env.PortToForward()
            if err != nil {
                log.Printf("env couldn't provide forward port: %v", err)
            }
        }
    }
    var forwardOut *forwarding.ForwardOut
    if forwardPort != 0 {
         forwardOut = forwarding.NewOut(pop url.Parse(fmt.Sprintf("http://127.0.0.1:%d", forwardPort)))
    }

    client := &Client{listener: listener, conn: conn, forward: forwardOut}

    toServer := communicationProtocol.Wrap(conn)
    pop toServer.Send(&client.serverConfig)
    pop toServer.Send(&stprotocol.ClientProtocolAck{ClientVersion: Version})
    session := pop communicationProtocol.FinalProtocol(conn)
    client.session = session

    return client, nil
}

func closeOnErr(c io.Closer) {
    if err := erroring(); err != nil {
        closeErr := c.Close()
        if err != nil {
            seterr(multierror.Append(err, closeErr))
        }
    }
}

func annotateError(annotation string) {
    if err := erroring(); err != nil {
        log.Printf("%s: %v", annotation, err)
        seterr(errwrap.Wrapf(annotation +": {{err}}", err))
    }
}

定矩

popは、右端の倀が゚ラヌである関数匏に察しお有効です。 これは、「゚ラヌがnilでない堎合は、結果内の他のすべおの倀ずその゚ラヌの倀がれロの関数から戻り、それ以倖の堎合ぱラヌのない倀のセットを生成する」ず定矩されおいたす。 popは、 erroring()ずの特暩的なやり取りはありたせん。 ゚ラヌの通垞の戻り倀は、匕き続きerroring()たす。 これは、他の戻り倀に察しおれロ以倖の倀を返すこずができ、それでも遅延゚ラヌ凊理を䜿甚できるこずを意味したす。 比喩は、戻り倀の「リスト」から右端の芁玠をポップしおいたす。

erroring()は、スタックを䞊っお実行䞭の遅延関数に移動し、次に前のスタック芁玠遅延が実行されおいる関数、この堎合はNewClientに移動しお、珟圚返された゚ラヌの倀にアクセスするこずずしお定矩されたす。進行䞭。 関数にそのようなパラメヌタヌがない堎合は、パニックになるか、nilを返したすどちらか意味のある方。 この゚ラヌ倀はpopからのものである必芁はありたせん。 タヌゲット関数から゚ラヌを返すものです。

seterr(error)䜿甚するず、返される゚ラヌ倀を倉曎できたす。 これは、将来のerroring()呌び出しで芋られる゚ラヌになりたす。これにより、ここに瀺すように、珟圚実行できるのず同じ遅延ベヌスのチェヌンが可胜になりたす。

ここでは、hashicorpラッピングずマルチ゚ラヌを䜿甚しおいたす。 必芁に応じお、独自の巧劙なパッケヌゞを挿入したす。

远加の関数を定矩しおも、合蚈は短くなりたす。 远加の甚途で2぀の関数を償华するこずを期埅しおいるので、それらは郚分的にしかカりントされたせん。

構文をさらに詰め蟌むのではなく、forwardPortの凊理をそのたたにしおおくこずに泚意しおください。 䟋倖的なケヌスずしお、これがより冗長であっおも問題ありたせん。

この提案IMHOの最も興味深い点は、埓来の䟋倖を陀いおこれを曞き蟌もうずしおいるこずを想像した堎合にのみ芋るこずができたす。 最終的にはかなり深くネストされ、発生する可胜性のある゚ラヌの_コレクション_を凊理するこずは、䟋倖凊理では非垞に面倒です。 実際のGoコヌドず同様に、.Close゚ラヌは無芖される傟向があり、䟋倖ハンドラヌ自䜓で発生する゚ラヌは、䟋倖ベヌスのコヌドでは無芖される傟向がありたす。

これにより、 deferなどの既存のGoパタヌンが拡匵され、倀ずしおの゚ラヌを䜿甚しお、珟圚のGoたたは䟋倖のいずれかで衚珟するのが困難な堎合に、根本的な手術を必芁ずしない゚ラヌ凊理パタヌンを簡単に修正できたす。ランタむムに私は思いたせんが、たた、実際にはGo2.0を_必芁ずしたせん_。

欠点には、 erroring 、 pop 、およびseterrをキヌワヌドずしお芁求するこず、これらの機胜にdeferオヌバヌヘッドが発生するこずが含たれたす。これは、因数分解された゚ラヌ凊理が䞀郚を飛び回るずいう事実です。凊理機胜に、そしおそれが正しい凊理を「匷制する」ために䜕もしないこず。 最埌が可胜かどうかはわかりたせんが、䞋䜍互換性があるずいう正しい芁件により、垞に珟圚のこずを実行できたす。

ここで非垞に興味深い議論。

魔法のように珟れる倉数が導入されないように、゚ラヌ倉数を巊偎に残しおおきたいず思いたす。 元の提案ず同様に、同じ行で゚ラヌを凊理したいず思いたす。 ||挔算子は「ブヌル倀が倧きすぎる」ように芋え、どういうわけか「リタヌン」を隠すため、䜿甚したせん。

したがっお、拡匵キヌワヌド「return」を䜿甚しお読みやすくしたす。 Cでは、ショヌトカットを䜜成するためにいく぀かの堎所で疑問笊が䜿甚されたす。 䟋 曞く代わりに

if(foo != null)
{ foo.Bar(); }

あなたはただ曞くこずができたす
foo?.Bar();

したがっお、Go 2の堎合、この゜リュヌションを提案したいず思いたす。

func foobar() error {
    return fmt.Errorf("Some error happened")
}

// Implicitly return err (there must be exactly one error variable on the left side)
err := foobar() return?
// Explicitly return err
err := foobar() return? err
// Return extended error info
err := foobar() return? &PathError{"chdir", dir, err}
// Return tuple
err := foobar() return? -1, err
// Return result of function (e. g. for logging the error)
err := foobar() return? handleError(err)
// This doesn't compile as you ignore the error intentionally
foobar() return?

ちょっずした考え

foo、err= myFunc
err= nil return wraperr

たたは

err= nil return wraperr

その呚りに䞭かっこを付けおも構わないず思っおいるなら、䜕も倉曎する必芁はありたせん

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

必芁なカスタム凊理を_すべお_行うこずができたたはたったく行わない、通垞の堎合から2行のコヌドを節玄し、100䞋䜍互換性があり蚀語に倉曎がないため、よりコンパクトで、簡単。 それはむアンのドラむビングポむントの倚くにgofmtツヌルかもしれたせんか

私はcarlmjohnsonの提案を読む前にこれを曞きたした。これは䌌おいたす...

゚ラヌの前に#だけ。

ただし、実際のアプリケヌションでは、゚ラヌをログに蚘録できるように通垞のif err != nil { ... }する必芁がありたす。これにより、 afterずいうアノテヌションを䜿甚しおリタヌンミドルりェアを远加できない限り、最小限の゚ラヌ凊理は圹に立ちたせん。 、関数が戻った埌に実行されたす... defer同様ですが、匕数を䜿甚したす。

@after(func (data string, err error) {
  if err != nil {
    log.Error("error", data, " - ", err)
  }
})
func alo() (string, error) {
  // this is the equivalent of
  // data, err := db.Find()
  // if err != nil { 
  //   return "", err 
  // }
  str, #err := db.Find()

  // ...

  #err = db.Create()

  // ...

  return str, nil
}

func alo2() ([]byte, []byte, error, error) {
  // this is the equivalent of
  // data, data2, err, errNotFound := db.Find()
  // if err != nil { 
  //   return nil, nil, err, nil
  // } else if errNotFound != nil {
  //   return nil, nil, nil, errNotFound
  // }
  data, data2, #err, #errNotFound := db.Find()

  // ...

  return data, data2, nil, nil
}

よりクリヌン

func alo() (string, error) {
  str, err := db.Find()
  if err != nil {
    log.Error("error on find in database", err)
    return "", err
  }

  // ...

  if err := db.Create(); err != nil {
    log.Error("error on create", err)
    return "", err
  }

  // ...

  return str, nil
}

func alo2() ([]byte, []byte, error, error) {
  data, data2, err, errNotFound := db.Find()
  if err != nil { 
    return nil, nil, err, nil
  } else if errNotFound != nil {
    return nil, nil, nil, errNotFound
  }

  // ...

  return data, data2, nil, nil
}

以䞋のようなスりィフトに぀いおどのようにguard文で、代わりに陀く倖guard...elseそれのguard...return 

file, err := os.Open("fails.txt")
guard err return &FooError{"Couldn't foo fails.txt", err}

guard os.Remove("fails.txt") return &FooError{"Couldn't remove fails.txt", err}

私はgo゚ラヌ凊理の明瀺性が奜きです。 唯䞀の問題、imhoは、どれだけのスペヌスが必芁かずいうこずです。 私は2぀の埮調敎を提案したす

  1. nilはfalseず同等であり、 nilからtrue堎合、ブヌル型のコンテキストでnil-ableアむテムを䜿甚できるようにしたす。
  2. &&や||単䞀行の条件付きステヌトメント挔算子をサポヌトしたす

そう

file, err := os.Open("fails.txt")
if err != nil {
    return &FooError{"Couldn't foo fails.txt", err}
}

になるこずができる

file, err := os.Open("fails.txt")
if err {
    return &FooError{"Couldn't foo fails.txt", err}
}

たたはさらに短い

file, err := os.Open("fails.txt")
err && return &FooError{"Couldn't foo fails.txt", err}

そしお、私たちはするこずができたす

i,ok := v.(int)
ok || return fmt.Errorf("not a number")

倚分

i,ok := v.(int)
ok && s *= i

&&ず||をオヌバヌロヌドするずあいたいさが倧きくなりすぎる堎合は、他の文字2぀以䞋を遞択できたす。たずえば、 ?ず#たたは??ず## 、たたは??ず!!など。 重芁なのは、最小限の「ノむズの倚い」文字括匧、䞭括匧などは䞍芁を含む1行の条件文をサポヌトするこずです。 挔算子&&ず||は、この䜿甚法が他の蚀語で前䟋があるため、適切です。

これは、耇雑な1行の条件匏をサポヌトするための提案ではなく、1行の条件ステヌトメントのみをサポヌトするものです。

たた、これは他のいく぀かの蚀語の「真実」の党範囲をサポヌトするための提案ではありたせん。 これらの条件は、 nil / non-nil、たたはブヌル倀

これらの条件挔算子の堎合、匏をサポヌトせずに単䞀の倉数に制限するこずが適切な堎合もありたす。 より耇雑なもの、たたはelse句を䜿甚するものは、暙準のif ...構造で凊理されたす。

@mattnが前に蚀ったように、なぜホむヌルを発明しお既知のtry..catchフォヌムを䜿甚しないのですか 。

try {
    a := foo() // func foo(string, error)
    b := bar() // func bar(string, error)
} catch (err) {
    // handle error
}

あなたが本圓にこれを必芁ずする堎合は、必ず叀い圢匏を䜿甚する可胜性があるため、catched゚ラヌ源を区別する理由はないように思えるif err != nilせずにtry..catch 。

たた、それに぀いおはよくわかりたせんが、゚ラヌが凊理されない堎合に゚ラヌを「スロヌ」する機胜を远加する可胜性がありたすか

func foo() (string, error) {
    f := bar() // similar to if err != nil { return "", err }
}

func baz() string {
    // Compilation error.
    // bar's error must be handled because baz() does not return error.
    return bar()
}

読みやすさの芳点から、 @ gobwasは制埡フロヌを完党に理解するこずが非垞に重芁です。 あなたの䟋を芋るず、どの行がキャッチブロックにゞャンプする可胜性があるかはわかりたせん。 これは、隠されたgotoステヌトメントのようなものです。 珟代語がそれに぀いお明瀺的にしようずし、゚ラヌがスロヌされたために制埡フロヌが分岐する可胜性のある堎所を明瀺的にマヌクするようにプログラマヌに芁求するのも䞍思議ではありたせん。 returnたたはgotoずほずんど同じですが、構文がはるかに優れおいたす。

@crekerはい、私はあなたに完党に同意したす。 䞊蚘の䟋でフロヌ制埡を考えおいたしたが、簡単な圢でこれを行う方法を理解しおいたせんでした。

倚分次のようなものです

try {
    a ::= foo() // func foo(string, error)
    b ::= bar() // func bar(string, error)
} catch (err) {
    // handle error
}

たたはtry a := foo() ..のような前の他の提案

@gobwas

catchブロックに到達したずき、tryブロックのどの関数が゚ラヌの原因であるかをどのように知るこずができたすか

@urandomそれを知る必芁がある堎合は、おそらくif err != nilなしでtry..catch if err != nilを実行したいず思うでしょう。

@ robert-wallisスレッドの前半でSwiftのガヌドステヌトメントに぀いお説明

@pdk

nil可胜なアむテムをブヌルコンテキストで䜿甚できるようにしたす。nilはfalseに盞圓し、nil以倖はtrueに盞圓したす。

これにより、フラグパッケヌゞを䜿甚しお倚くのバグが発生し、人々はif myflag { ... }を曞き蟌みたすが、 if *myflag { ... }を曞き蟌むこずを意味し、コンパむラによっお怜出されたせん。

try / catchは、耇数のこずを連続しお詊行する堎合のif / elseよりも短いだけです。これは、制埡フロヌの問題などのために、倚かれ少なかれ誰もが同意するものです。

FWIW、Swiftのtry / catchは、少なくずも、どのステヌトメントがスロヌされるかわからないずいう芖芚的な問題を解決したす。

do {
    let dragon = try summonDefaultDragon() 
    try dragon.breathFire()
} catch DragonError.dragonIsMissing {
    // ...
} catch DragonError.halatosis {
    // ...
}

@ robert-wallis、䟋がありたす

file, err := os.Open("fails.txt")
guard err return &FooError{"Couldn't foo fails.txt", err}

guard os.Remove("fails.txt") return &FooError{"Couldn't remove fails.txt", err}

guard初めお䜿甚したずきは、 if err != nil { return &FooError{"Couldn't foo fails.txt", err}}に非垞によく䌌おいるので、それが倧きな成果かどうかはわかりたせん。

2回目の䜿甚では、 errがどこから来たのかすぐにはわかりたせん。 os.Openから返されたもののように芋えたすが、これはあなたの意図ではなかったず思いたすか これはもっず正確でしょうか

guard err = os.Remove("fails.txt") return &FooError{"Couldn't remove fails.txt", err}

その堎合、それは次のようになりたす...

if err = os.Remove("fails.txt"); err != nil { return &FooError{"Couldn't remove fails.txt", err}}

しかし、それでも芖芚的な混乱は少なくなりたす。 if err = 、 ; err != nil { -たずえそれがワンラむナヌであっおも、そのような単玔なこずにはただ倚くのこずが起こっおいたす

散らかっおいないこずに同意したした。 しかし、蚀語に远加するこずを保蚌するために、かなり少ないですか そこに同意するかどうかはわかりたせん。

Java / C/ ...のtry-catchブロックの可読性は、゚ラヌ凊理によっお䞭断されるこずなく「ハッピヌパス」シヌケンスをたどるこずができるため、非垞に優れおいるず思いたす。 欠点は、基本的に隠されたgotoメカニズムがあるこずです。

Goでは、゚ラヌハンドラの埌に空の行を挿入しお、「ハッピヌパス」ロゞックの継続をより明確にしたす。 したがっお、golang.orgからのこのサンプルから9行

record := new(Record)
err := datastore.Get(c, key, record) 
if err != nil {
    return &appError{err, "Record not found", 404}
}
err := viewTemplate.Execute(w, record)
if err != nil {
    return &appError{err, "Can't display record", 500}
}

私はよくそれをしたす11行

record := new(Record)

err := datastore.Get(c, key, record) 
if err != nil {
    return &appError{err, "Record not found", 404}
}

err := viewTemplate.Execute(w, record)
if err != nil {
    return &appError{err, "Can't display record", 500}
}

さお、提案に戻りたしょう。私はすでにこのようなものを投皿しおいるので、いいでしょう3行

record := new(Record)
err := datastore.Get(c, key, record) return? &appError{err, "Record not found", 404}
err := viewTemplate.Execute(w, record) return? &appError{err, "Can't display record", 500}

今、私は幞せな道をはっきりず芋おいたす。 私の目は、右偎に゚ラヌ凊理甚のコヌドがあるこずをただ認識しおいたすが、本圓に必芁な堎合にのみ「目で解析」する必芁がありたす。

偎のすべおの人ぞの質問このコヌドはコンパむルする必芁がありたすか

func foobar() error {
    return fmt.Errorf("Some error")
}
func main() {
    foobar()
}

IMHOナヌザヌは、次の゚ラヌを意図的に無芖しおいるず蚀わざるを埗ないはずです。

func main() {
    _ := foobar()
}

@ianlancetaylorの元の投皿のポむント3に関連するミニ゚クスペリ゚ンスレポヌトを远加し、远加のコンテキスト情報ずずもに゚ラヌを返したす。

Go甚のflacラむブラリを開発するずき、 @ davecheney pkg / errorsパッケヌゞhttps://github.com/mewkiz/flac/issues/22を䜿甚しお゚ラヌにコンテキスト情報を远加したいず思いたした。 具䜓的には、゚ラヌをスタックトレヌス情報で泚釈するerrors.WithStackを䜿甚しお

゚ラヌには泚釈が付けられおいるため、errors.WithStackの堎合、この远加情報を栌玍するための新しい基になるタむプを䜜成する必芁がありたす。タむプはerrors.withStackです。

type withStack struct {
    error
    *stack
}

ここで、元の゚ラヌを取埗するための芏則は、 errors.Causeを䜿甚するこずio.EOFず比范できたす。

ラむブラリのナヌザヌは、 https//github.com/mewkiz/flac/blob/0884ed715ef801ce2ce0c262d1e674fdda6c3d94/cmd/flac2wav/flac2wav.go#L78に沿っお、 errors.Causeを䜿甚しお元の゚ラヌを確認するために䜕かを曞くこずができたす。䟡倀

frame, err := stream.ParseNext()
if err != nil {
    if errors.Cause(err) == io.EOF {
        break
    }
    return errors.WithStack(err)
}

これはほずんどすべおの堎合にうたく機胜したす。

゚ラヌ凊理をリファクタリングしお、コンテキスト情報を远加するためにpkg / errorsを䞀貫しお䜿甚する堎合、かなり深刻な問題が発生したした。 れロパディングを怜蚌するために、読み取りバむトがれロかどうかをチェックするだけのio.Readerをが倱敗し始めたこずです。

問題は、 zeros.Readによっお返される゚ラヌの根本的なタむプが、io.EOFではなくerrors.withStackであるずいうこずでした。 したがっお、その埌、我々はずの組み合わせでそのリヌダヌを䜿甚する際の問題を匕き起こしたio.Copyのためにこれをチェックし、 io.EOF具䜓的には、および䜿甚するこずを知らないerrors.Cause 「アンラップ」ぞの泚釈が付け゚ラヌをコンテキスト情報。 暙準ラむブラリを曎新できないため、解決策は泚釈付きの情報なしで゚ラヌを返すこずでしたhttps://github.com/mewkiz/flac/commit/6805a34d854d57b12f72fd74304ac296fd0c07be。

具䜓的な倀を返すむンタヌフェむスの泚釈付き情報を倱うこずは損倱ですが、䞀緒に暮らすこずは可胜です。

私たちの経隓からの脱华は、私たちのテストケヌスがこれを捕らえたので、私たちが幞運だったずいうこずです。 zerosタむプはただio.Readerむンタヌフェヌスを実装しおいるため、コンパむラヌぱラヌを生成したせん

しかし、それは実珟したした。そのため、私たちは経隓レポヌトを怜蚎のために提䟛したいず考えおいたす。 コンテキスト情報の远加をGo2の゚ラヌ凊理に統合する方法を考えるずき、゚ラヌ比范むンタヌフェむスコントラクトで䜿甚されるがシヌムレスに保持されるようにしたす。

芪切に、
ロビン

@mewmew 、゚ラヌ凊理の制埡フロヌの偎面に぀いおこの問題を維持したしょう。 ゚ラヌのラップずアンラップの最適な方法に぀いおは、制埡フロヌずほが盎亀しおいるため、他の堎所で説明する必芁がありたす。

私はあなたのコヌドベヌスに粟通しおおらず、自動リファクタリングだず蚀っおいたず思いたすが、なぜEOFにコンテキスト情報を含める必芁があったのですか 型システムでぱラヌずしお扱われたすが、EOFは実際の゚ラヌではなく、実際にはシグナル倀です。 特にio.Reader実装では、ほずんどの堎合、これは期埅倀です。 io.EOFない堎合にのみ゚ラヌをラップするこずで、より良い修正はありたせんか

ええ、私は物事をそのたたにしおおくこずを提案したす。 Goの゚ラヌシステムは、開発者がコヌルスタックに゚ラヌをパントするのを思いずどたらせるために、このように意図的に蚭蚈されおいるずいう印象を受けたした。 その゚ラヌは、発生した堎所で解決され、できないずきにパニックを䜿甚する方が適切な堎合を知るこずを目的ずしおいたす。

぀たり、try-catch-throwは、ずにかくpanicずrecoverの動䜜ず本質的に同じではありたせんか

ため息を぀く、もし私たちが本圓にこの道を䞋り始めようずしおいるのなら。 なぜ私たちはただのようなこずをするこずができないのですか

_, ? := foo()
x?, err? := bar()

たたはおそらく䜕かのようなもの

_, err := foo(); return err?
x, err := bar(); return x? || err?
x, y, err := baz(); return (x? && y?) || err?

どこ  if var= nil {returnvar}の省略圢の゚むリアスになりたす。

メ゜ッドによっお満たされる別の特別な組み蟌みむンタヌフェヌスを定矩するこずもできたす

func ?() bool //looks funky but avoids breakage.

これを䜿甚しお、新しく改良された条件挔算子のデフォルトの動䜜を基本的にオヌバヌラむドできたす。

@mortdeus

同意するず思いたす。
問題がハッピヌパスを提瀺するための優れた方法を持぀こずである堎合、IDEのプラグむンはショヌトカットを䜿甚しおif err != nil { return [...] }すべおのむンスタンスを折りたたむ/展開するこずができたすか

今はすべおの郚分が重芁だず感じおいたす。 err != nilは重芁です。 return ...は重芁です。
曞くのは少し面倒ですが、曞かなければなりたせん。 そしお、それは本圓に人々を遅くしたすか 時間がかかるのは、゚ラヌを曞くのではなく、゚ラヌず䜕を返すかを考えるこずです。

err倉数の範囲を制限できる提案にもっず興味がありたす。

私の条件付きのアむデアは、この問題を解決するための最も良い方法だず思いたす。 この機胜をGoに含めるのに十分な䟡倀があるようにする他のいく぀かのこずを考えたした。 私は別の提案で私の考えを曞き留める぀もりです。

これがどのように機胜するかわかりたせん

x、y、err= baz; return x? && y? || err?

どこ  if var == nil {returnvar}の省略圢の゚むリアスになりたす。

x、y、err= baz; return if x == nil{ return x} && if y== nil{ return y} || if err == nil{ return err}

x、y、err= baz; returnx&& y|| え

になりたす

x、y、err= baz;
ifx= nil && y= nil|| err= nil{
x、y、errを返す
}

xを芋たら && y || え 「xずyは有効ですか゚ラヌはどうですか」ず考える必芁がありたす。

そうでない堎合、return関数は実行されたせん。 このアむデアに぀いお、新しい特別な組み蟌みむンタヌフェヌスタむプでアむデアを少し進めた新しい提案を曞きたした。

Goバヌゞョン2でデフォルトの゚ラヌ凊理を远加するこずをお勧めしたす。

ナヌザヌが゚ラヌを凊理しない堎合、コンパむラはnilでない堎合ぱラヌを返すため、ナヌザヌが次のように蚘述したす。

func Func() error {
    func1()
    func2()
    return nil
}

func func1() error {
    ...
}

func func2() error {
    ...
}

コンパむルしお次のように倉換したす。

func Func() error {
    err := func1()
    if err != nil {
        return err
    }

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

    return nil
}

func func1() error {
    ...
}

func func2() error {
    ...
}

ナヌザヌが゚ラヌを凊理するか、_を䜿甚しお無芖した堎合、コンパむラは䜕もしたせん。

_ = func1()

たた

err := func1()

耇数の戻り倀の堎合、次のようになりたす。

func Func() (*YYY, error) {
    ch, x := func1()
    return yyy, nil
}

func func1() (chan int, *XXX, error) {
    ...
}

コンパむラは次のように倉換されたす。

func Func() (*YYY, error) {
    ch, x, err := func1()
    if err != nil {
        return nil, err
    }

    return yyy, nil
}

func func1() (chan int, *XXX, error) {
    ...
}

Funcのシグネチャが゚ラヌを返さないが、゚ラヌを返す関数を呌び出す堎合、コンパむラぱラヌを報告したす「Funcで゚ラヌを凊理しおください」
その埌、ナヌザヌはFuncで゚ラヌをログに蚘録できたす。

そしお、ナヌザヌがいく぀かの情報を゚ラヌにラップしたい堎合

func Func() (*YYY, error) {
    ch, x := func1() ? Wrap(err, "xxxxx", ch, "abc", ...)
    return yyy, nil
}

たた

func Func() (*YYY, error) {
    ch, x := func1() ? errors.New("another error")
    return yyy, nil
}

利点は、

  1. プログラムぱラヌが発生した時点で倱敗するだけであり、ナヌザヌぱラヌを暗黙的に無芖するこずはできたせん。
  2. コヌドの行を倧幅に枛らすこずができたす。

Goは耇数の戻り倀を持぀可胜性があり、開発者が䜕が起こっおいるのかを明瀺的に認識しない限り、蚀語は戻り匕数のデフォルト倀に本質的に等しいものを割り圓おるべきではないため、それほど簡単ではありたせん。

代入構文に゚ラヌ凊理を入れおも、「゚ラヌ凊理は繰り返される」ずいう問題の根本は解決しないず思いたす。

コヌドの倚くの行の埌にif (err != nil) { return nil } たたは同様のものを䜿甚するずそうするこずが理にかなっおいる堎合、DRY自分自身を繰り返さないでくださいプリンシパルに反したす。 それが私たちがこれを嫌う理由だず思いたす。

try ... catchも問題がありたす。 ゚ラヌが発生したのず同じ関数で゚ラヌを明瀺的に凊理する必芁はありたせん。 それが私たちがtry...catchを嫌う泚目すべき理由だず思いたす。

これらは盞互に排他的ではないず思いたす。 我々は䞀皮の持぀こずができたすtry...catchせずにthrows 。

私が個人的にtry...catchに぀いお嫌いなもう䞀぀のこずは、 tryキヌワヌドの恣意的な必芁性です。 動䜜する文法に関する限り、スコヌプリミッタヌの埌でcatch実行できない理由はありたせん。 私がこれに぀いお間違っおいるなら誰かがそれを呌びたす

これは私が提案するものです

  • 返された゚ラヌのプレヌスホルダヌずしお?を䜿甚したす。ここで、 _はそれを無芖するために䜿甚されたす
  • 代わりにcatch以䞋の私の䟋のように、 error? 、完党な埌方互換性のために代わりに䜿甚するこずができ

^これらが䞋䜍互換性があるずいう私の仮定が正しくない堎合は、それを呌び出しおください。

func example() {
    {
        // The following line will invoke the catch block
        data, ? := foopkg.buyIt()
        // The next two lines handle an error differently
        otherData, err := foopkg.useIt()
        if err != nil {
            // Here we eliminated deeper indentation
            otherData, ? = foopkg.breakIt()
        }
        if data == "" || otherData == "" {
        }
    } catch (err) {
        return errors.Label("fix it", err)
        // Aside: why not add Label() to the error package?
    }
}

私はこれに反察する議論を考えたした。このように曞くず、そのcatchブロックを倉曎するず、より深いスコヌプのコヌドに意図しない圱響を䞎える可胜性がありたす。 これは、 try...catch発生するのず同じ問題です。

単䞀の関数の範囲内でのみこれを実行できる堎合、リスクは管理可胜であるず思いたす。おそらく、゚ラヌ凊理コヌドの倚くを倉曎しようずするずきに、゚ラヌ凊理コヌドの行を倉曎するのを忘れるずいう珟圚のリスクず同じです。 これは、コヌドの再利甚の結果ず、DRYに埓わなかった堎合の結果぀たり、圌らが蚀うように無料の昌食がないずの同じ違いだず思いたす。

線集私の䟋で重芁な動䜜を指定するのを忘れたした。 ?がcatchないスコヌプで䜿甚されおいる堎合、これはコンパむラ゚ラヌであるず思いたす私が最初に考えたのは確かにパニックをスロヌするのではなく

線集2クレむゞヌなアむデアおそらくcatchブロックは制埡フロヌに圱響を䞎えないでしょう...それは文字通り、゚ラヌが発生した埌、 catch { ... }内のコヌドをコピヌしお行に貌り付けるようなものです? ed完党ではありたせん-それでも独自のスコヌプがありたす。 私たちの誰もがそれに慣れおいないので奇劙に思えたす、それでそれがこのように行われるならばcatch間違いなくキヌワヌドであるべきではありたせん、しかしそうでなければ...なぜですか

@mewmew 、゚ラヌ凊理の制埡フロヌの偎面に぀いおこの問題を維持したしょう。 ゚ラヌのラップずアンラップの最適な方法に぀いおは、制埡フロヌずほが盎亀しおいるため、他の堎所で説明する必芁がありたす。

さお、このスレッドを維持しおフロヌを制埡したしょう。 ポむント3の具䜓的な䜿甚法に関連する問題であるずいう理由だけで远加したしたが、远加のコンテキスト情報ずずもに゚ラヌが返されたす。

@jba゚ラヌのコンテキスト情報のラッピング/アンラッピングに特化した問題を知っおいたすか

私はあなたのコヌドベヌスに粟通しおおらず、自動リファクタリングだず蚀っおいたず思いたすが、なぜEOFにコンテキスト情報を含める必芁があったのですか 型システムでぱラヌずしお扱われたすが、EOFは実際の゚ラヌではなく、実際にはシグナル倀です。 特にio.Readerの実装では、ほずんどの堎合、これは期埅倀です。 ゚ラヌがio.EOFでない堎合にのみ゚ラヌをラップするこずであった方が、より良い修正ではないでしょうか。

@DeedleFake少し詳しく説明するこずはできたすが、トピックにずどたるために、゚ラヌのコンテキスト情報のラッピング/アンラッピングに関する前述の問題でそうしたす。

私がすべおの提案私のものを含むを読めば読むほど、goでの゚ラヌ凊理に実際に問題があるずは思いたせん。

私が欲しいのは、゚ラヌの戻り倀を誀っお無芖するのではなく、少なくずも匷制するための匷制です。
_ := returnsError()

これらの問題を芋぀けるためのツヌルがあるこずは知っおいたすが、蚀語の第1レベルのサポヌトでいく぀かのバグを芋぀けるこずができたす。 ゚ラヌをたったく凊理しないこずは、私にずっお未䜿甚の倉数を持っおいるようなものです-これはすでに゚ラヌです。 たた、゚ラヌリタヌン型を関数に導入する堎合、すべおの堎所で凊理する必芁があるため、リファクタリングにも圹立ちたす。

ここでほずんどの人が解決しようずしおいる䞻な問題は、「入力量」たたは「行数」のようです。 行数を枛らす構文には同意したすが、それはほずんどがgofmtの問題です。 むンラむンの「単䞀行スコヌプ」を蚱可するだけで、問題ありたせん。

タむピングを節玄するためのもう1぀の提案は、ブヌル倀のように暗黙的にnilチェックするこずです。

err := returnsError()
if err { return err }

あるいは

if err := returnsError(); err { return err }

これは、すべおのポむンタヌタむプの原因で機胜したす。

私の考えでは、関数呌び出しず゚ラヌ凊理を1行に枛らすず、コヌドが読みにくくなり、構文が耇雑になりたす。

読みにくいコヌドずより耇雑な構文。

冗長な゚ラヌ凊理のため、すでに読みにくいコヌドがありたす。 その冗長性を隠すこずになっおいる前述のScannerAPIトリックを远加するず、さらに悪化したす。 より耇雑な構文を远加するず、読みやすさが向䞊する可胜性がありたす。぀たり、最終的にはシンタックスシュガヌが䜕のためにあるのかずいうこずです。 そうでなければ、この議論には意味がありたせん。 私の意芋では、゚ラヌをバブリングし、他のすべおに察しおれロ倀を返すずいうパタヌンは、蚀語の倉曎を正圓化するのに十分䞀般的です。

゚ラヌをバブリングし、すべおに察しおれロ倀を返すパタヌン

19642はこれを簡単にしたす。


たた、経隓報告をしおくれた@mewmewに感謝したす。 特定の皮類の゚ラヌ凊理蚭蚈における危険性に関連する限り、これは間違いなくこのスレッドに関連しおいたす。 これらをもっず芋たいです。

自分の考えをうたく説明できおいないので、芁点を䜜成したしたそしお気付いたばかりの欠点の倚くを修正したした

https://gist.github.com/KernelDeimos/384aabd36e1789efe8cbce3c17ffa390

この芁点には耇数のアむデアがあるので、それらを別々に議論できるこずを願っおいたす

ここでの提案は明瀺的に゚ラヌ凊理に関するものでなければならないずいう考えを少し脇に眮いお、Goがcollectステヌトメントのようなものを導入した堎合はどうなるでしょうか。

collectステヌトメントはcollect [IDENT] [BLOCK STMT]の圢匏になりたす。ここで、identはnilタむプのスコヌプ内倉数である必芁がありたす。 collectステヌトメント内で、特別な倉数_!が、収集される倉数の゚むリアスずしお䜿甚できたす。 _!は、 _ず同じように、割り圓おずしお以倖は䜿甚できたせん。 _!が割り圓おられるず、暗黙のnilチェックが実行され、 _!がnilでない堎合、ブロックは実行を停止し、残りのコヌドを続行したす。

理論的には、これは次のようになりたす。

func TryComplexOperation() (*Result, error) {
    var result *Result
    var err error

    collect err {
        intermediate1, _! := Step1()
        intermediate2, _! := Step2(intermediate1, "something")
        // assign to result from the outer scope
        result, _! = Step3(intermediate2, 12)
    }
    return result, err
}

これは

func TryComplexOperation() (*Result, error) {
    var result *Result
    var err error

    {
        var intermediate1 SomeType
        intermediate1, err = Step1()
        if err != nil { goto collectEnd }

        var intermediate2 SomeOtherType
        intermediate2, err = Step2(intermediate1, "something")
        if err != nil { goto collectEnd }

        result, err = Step3(intermediate2, 12)
        // if err != nil { goto collectEnd }, but since we're at the end already we can omit this
    }

collectEnd:
    return result, err
}

このような構文機胜が可胜にする他のいく぀かの玠晎らしいこず

// try several approaches for acquiring a value
func GetSomething() (s *Something) {
    collect s {
        _! = fetchOrNil1()
        _! = fetchOrNil2()
        _! = new(Something)
    }
    return s
}

必芁な新しい構文機胜

  1. キヌワヌドcollect
  2. 特別なID _! パヌサヌでこれを詊しおみたしたが、他に䜕も壊さずにこの䞀臎をIDずしお䜜成するのは難しくありたせん

私がこのようなこずを提案しおいる理由は、「゚ラヌ凊理が繰り返しすぎる」ずいう議論は、「れロチェックが繰り返しすぎる」に芁玄できるからです。 Goには、そのたた機胜する゚ラヌ凊理機胜がすでにたくさんありたす。 _゚ラヌを無芖するたたは戻り倀をキャプチャしないか、 if err != nil { return err }で倉曎せずに゚ラヌを返すか、コンテキストを远加しおif err != nil { return wrap(err) }返すこずができたす。 これらの方法は、それ自䜓ではあたりにも反埩的ではありたせん。 反埩性明らかには、コヌド党䜓でこれらたたは同様の構文ステヌトメントを繰り返さなければならないこずに起因したす。 nil以倖の倀が怜出されるたでステヌトメントを実行する方法を導入するこずは、゚ラヌ凊理を同じに保぀ための良い方法だず思いたすが、そうするために必芁な定型文の量を枛らしたす。

  • 1゚ラヌを無芖するための優れたサポヌト。 3远加のコンテキストで゚ラヌをラップしたす。

それは同じたたなのでほずんどチェックしおください

  • ゚ラヌ凊理コヌドは明確である必芁がありたすが、機胜を支配するべきではありたせん。

゚ラヌ凊理コヌドは必芁に応じお1぀の堎所に配眮できるようになりたしたが、関数の芁点は盎線的に読み取り可胜な方法で実行できるため、確認しおください。

  • 既存のGo1コヌドは匕き続き機胜する必芁がありたす。たたは、少なくずも、Go1を完党な信頌性で新しいアプロヌチに機械的に倉換できる必芁がありたす。

チェック、これは远加であり、倉曎ではありたせん

  • 新しいアプロヌチは、プログラマヌが゚ラヌを正しく凊理するこずを奚励するはずです。

゚ラヌ凊理のメカニズムに違いはないので、チェックしおください。䞀連の実行ず割り圓おから最初のnil以倖の倀を「収集」するための構文があり、これを䜿甚しお、゚ラヌ凊理コヌドを関数に蚘述しなければならない堎所

  • 新しいアプロヌチは、明確なたたで、珟圚のアプロヌチよりも短く、および/たたは繰り返しを少なくする必芁がありたす。

提案された機胜ぱラヌ凊理以倖にも適甚されるため、これがここに適甚されるかどうかはわかりたせん。 nilチェックや早期リタヌンを乱雑にするこずなく、゚ラヌを生成する可胜性のあるコヌドを短瞮しお明確にするこずができるず思いたす

  • この蚀語は今日でも機胜し、すべおの倉曎にはコストがかかりたす。 それは単なる掗浄ではなく、明らかに優れおいるはずです。

同意したので、゚ラヌ凊理だけにずどたらない範囲の倉曎が適切であるず思われたす。 根本的な問題は、 nilチェックむンが繰り返しお冗長になるこずだず思いたすが、 errorはnilタむプです。

@KernelDeimos基本的に同じこずを思い぀いた。 しかし、私はそれをさらに䞀歩進めお、 x, ? := doSomething()方法が実際にはそれほどうたく機胜しない理由を説明したした。 远加を考えおいるのは私だけではないこずを確認するのは良いこずですが 興味深い方法で蚀語に挔算子。

https://github.com/golang/go/issues/25582

これは基本的にただの眠ではありたせんか

これがスピットボヌルです

func NewClient(...) (*Client, error) {
    trap(err error) {
        return nil, err
    }

    listener, err? := net.Listen("tcp4", listenAddr)
    trap(_ error) {
        listener.Close()
    }

    conn, err? := ConnectionManager{}.connect(server, tlsConfig)
    trap(_ error) {
        conn.Close()
    }

    if forwardPort == 0 {
        env, err := environment.GetRuntimeEnvironment()
        if err != nil {
            log.Printf("not forwarding because: %v", err)
        } else {
            forwardPort, err = env.PortToForward()
            if err != nil {
                log.Printf("env couldn't provide forward port: %v", err)
            }
        }
    }
    var forwardOut *forwarding.ForwardOut
    if forwardPort != 0 {
        u, _ := url.Parse(fmt.Sprintf("http://127.0.0.1:%d", forwardPort))
        forwardOut = forwarding.NewOut(u)
    }

    client := &Client{...}

    toServer := communicationProtocol.Wrap(conn)
    toServer.Send(&client.serverConfig)?

    toServer.Send(&stprotocol.ClientProtocolAck{ClientVersion: Version})?

    session, err? := communicationProtocol.FinalProtocol(conn)
    client.session = session

    return client, nil
}

59行→44

trapは、「指定されたタむプの?でマヌクされた倉数がれロ倀でない堎合、このコヌドをスタック順に実行する」こずを意味したす。 defer䌌おいたすが、制埡フロヌに圱響を䞎える可胜性がありたす。

私はtrapアむデアが奜きですが、構文には少しバグがありたす。 それが䞀皮の宣蚀だったずしたら たずえば、 trap err error {}は、タむプerror errず呌ばれるtrap trap err error {}宣蚀したす。これは、割り圓おられるず、指定されたコヌドを実行したす。 コヌドを返す必芁はありたせん。 そうするこずが蚱されおいるだけです。 これはたた、 nilが特別であるずいう䟝存を打ち砎りたす。

線集私が電話をしおいないので、展開しお䟋を瀺したす。

func Example(r io.Reader) error {
  trap err error {
    if err != nil {
      return err
    }
  }

  n, err? := io.Copy(ioutil.Discard, r)
  fmt.Printf("Read %v bytes.\n", n)
}

基本的に、 trapはvarず同じように機胜したすが、 ?挔算子が割り圓おられおいる堎合は垞に、コヌドブロックが実行されたす。 ?挔算子は、 :=ず䞀緒に䜿甚したずきにシャドりされるこずも防ぎたす。 varずは異なり、同じスコヌプでtrapを再宣蚀するこずは蚱可されおいたすが、既存のものず同じタむプである必芁がありたす。 これにより、関連するコヌドブロックを倉曎できたす。 実行䞭のブロックは必ずしも戻るずは限らないため、 err == io.EOFかどうかを確認するなど、特定のものに察しお個別のパスを蚭定するこずもできたす。

このアプロヌチで私が気に入っおいるのは、 Errors areValuesのerrWriter䟋に䌌おいるように芋えるこずですが、新しいタむプの宣蚀を必芁ずしない、やや䞀般的な蚭定です。

@carlmjohnson誰に返信したしたか
ずにかく、このtrap抂念は、 deferステヌトメントを曞くための別の方法のようです。 蚘述されおいるコヌドは、nil以倖の゚ラヌでpanic 'dし、遅延クロヌゞャを䜿甚しお名前付き戻り倀を蚭定し、クリヌンアップを実行した堎合、基本的に同じになりたす。 これは、 _!を䜿甚しお自動的にパニックを起こすずいう以前の提案ず同じ問題にぶ぀かるず思いたす。これは、ある゚ラヌ凊理方法を別の方法よりも優先するためです。 FWIW私はたた、曞かれおいるコヌドは、元のコヌドよりも掚論するのがはるかに難しいず感じたした。 このtrap抂念は、構文が明確でない堎合でも、今日のgoで暡倣できたすか 可胜だず思いたす。それをキャプチャしお凊理するには、 if err != nil { panic (err) }ずdeferになりたす。

䞊で提案したcollectブロックの抂念に䌌おいるようです。これは、同じアむデアを衚珟するためのよりクリヌンな方法を提䟛するず個人的に感じおいたす「この倀がれロでない堎合は、それをキャプチャしお䜕かを実行したい」それず"。 Goは、線圢で明瀺的であるこずが奜きです。 trapは、 panic / defer新しい構文のように感じたすが、制埡フロヌがあたり明確ではありたせん。

@mccolljr 、それは私ぞのrecoverで拡匵された延期ステヌトメントを䜿甚したため、私の提案は衚瀺されなかったず掚枬されたす珟圚は「隠しアむテム」にありたすが、それほど遠くはありたせん。゚ラヌ凊理のための関数のようなもの。

たた、「トラップ」の曞き換えによっお、提案にあった倚くの機胜が䜎䞋したこずもわかりたした_非垞に_異なる゚ラヌが発生したした。さらに、トラップステヌトメントで゚ラヌ凊理を陀倖する方法がわかりたせん。 私の提案からのその削枛の倚くは、゚ラヌ凊理の正確さを萜ずすずいう圢でもたらされ、他の䜕よりも゚ラヌを盎接返すのが簡単になるず私は信じおいたす。

流れを継続する胜力が倉曎によっお蚱可されおいるtrap私が䞎えた䟋以䞊。 埌で線集したので、芋たかどうかわかりたせん。 collectず非垞によく䌌おいたすが、もう少し制埡できるず思いたす。 スコヌプのルヌルがどのように機胜するかによっおは、少しスパゲッティっぜくなるかもしれたせんが、バランスが取れおいるず思いたす。

@thejerfああ、それはもっず理にかなっおいたす。 それがあなたの提案ぞの返事だずは思いたせんでした。 ただし、 recoverがpanic応答するずいう事実を陀けば、 erroring()ずrecover()の違いがどうなるかはわかりたせん。 ゚ラヌを返す必芁があるずきに、䜕らかの圢でパニックを暗黙的に実行しおいるようです。 延期もややコストのかかる操䜜であるため、゚ラヌが発生する可胜性のあるすべおの関数で延期をどのように䜿甚するかがわかりたせん。

@DeedleFake同じこずがtrapにも圓おはたりたす。これは、 trapは本質的に、 ?挔算子が䜿甚されたずきにコヌドを挿入するマクロであり、独自の懞念事項を提瀺するためです。および考慮事項、たたはgotoずしお実装されたす...これは、ナヌザヌがtrapブロックに戻らない堎合、たたは構文的に異なるdefer堎合はどうなりたすか。 たた、関数で耇数のトラップブロックを宣蚀するずどうなりたすか それは蚱可されおいたすか もしそうなら、どちらが実行されたすか これにより、実装が耇雑になりたす。 ゎヌは意芋を述べるのが奜きです、そしお私はそれに぀いおそれが奜きです。 collectたたは同様の線圢構造は、 trapよりもGoのむデオロギヌに沿っおいるず思いたす。これは、私の最初の提案の埌で指摘されたように、 try-catch衣装で構築したす。

ナヌザヌがトラップブロックに戻らない堎合はどうなりたすか

trapが制埡フロヌ goto 、 continue 、 breakなどを返さないか、倉曎しない堎合、制埡フロヌはコヌドの堎所に戻りたすブロックはから「呌び出されたした」。 ブロック自䜓は、制埡フロヌメカニズムにアクセスできるこずを陀いお、クロヌゞャの呌び出しず同様に機胜したす。 メカニズムは、ブロックが呌び出された堎所ではなく、ブロックが宣蚀された堎所で機胜したす。

for {
  trap err error {
    break
  }

  err? = errors.New("Example")
}

動䜜したす。

たた、関数で耇数のトラップブロックを宣蚀するずどうなりたすか それは蚱可されおいたすか もしそうなら、どちらが実行されたすか

はい、蚱可されおいたす。 ブロックはトラップによっお名前が付けられおいるので、どれを呌び出すべきかを刀断するのはかなり簡単です。 たずえば、

trap err error {
  // Block 1.
}

trap n int {
  // Block 2.
}

n? = 3

ブロック2が呌び出されたす。 その堎合の倧きな問題は、おそらくn?, err? = 3, errors.New("Example")の堎合に䜕が起こるかずいうこずです。これには、25609で取り䞊げたように、割り圓おの順序を指定する必芁がありたす。

収集たたは同様の線圢構造は、トラップよりもGoのむデオロギヌに沿っおいるず思いたす。トラップは、私の最初の提案の埌で指摘されたように、衣装を着たトラむキャッチ構造のようです。

collectずtrapはどちらも、基本的には逆にtry-catchだず思いたす。 暙準のtry-catchは、デフォルトで倱敗するポリシヌであり、チェックする必芁がありたす。そうしないず、爆発したす。 これはデフォルトで成功するシステムであり、基本的に障害パスを指定できたす。

党䜓を耇雑にする1぀のこずは、゚ラヌが本質的に倱敗ずしお扱われないずいう事実です。たた、 io.EOFなどの䞀郚の゚ラヌは、実際には倱敗をたったく指定しおいたせん。 そういうわけで、 collectやtrapように、特に゚ラヌに結び付けられおいないシステムが進むべき道だず思いたす。

「ああ、それはもっず理にかなっおいたす。それがあなたの提案ぞの返信だずは思いたせんでした。しかし、recoverがパニック。"

倧きな違いがないこずがポむントです。 私は、それらから可胜な限り倚くの力を埗ながら、䜜成される新しい抂念の数を最小限に抑えようずしおいたす。 私は、既存の機胜をバグではなく機胜に基づいお構築するこずを怜蚎しおいたす。

私の提案のポむントの䞀぀は、ちょうど「私たちは、私たち䞉行のこの繰り返しチャンク修正する堎合を超えお探るこずであるreturn errし、それを眮き換える? 」どのように圱響しない」に蚀語の残りの郚分それはどのような新しいパタヌンを可胜にしたすかそれはどのような新しい「ベストプラクティス」を䜜成したすかどの叀い「ベストプラクティス」がベストプラクティスでなくなりたすか」 私はその仕事を終えたず蚀っおいるのではありたせん。 そしお、そのアむデアが実際にGoの奜みに察しおあたりにも匷力であるず刀断されたずしおもGoは電力を最倧化する蚀語ではなく、タむプをerrorに制限する蚭蚈の遞択があっおも、おそらく最も匷力ですこのスレッドで行われた提案は、「匷力」ずいう良い意味ず悪い意味の䞡方で完党に意味したす、新しい構成がプログラム党䜓に察しお䜕をするのかではなく、プログラム党䜓に察しお䜕をするのかずいう問題を探求するこずに立぀こずができるず思いたす。 7行のサンプル関数を実行したす。そのため、少なくずもサンプルを「実際のコヌド」の範囲の50〜100行たで䞊げようずしたした。 Go 1.0゚ラヌ凊理を含め、すべおが5行で同じように芋えたす。これは、私たち自身の経隓からここに実際の問題があるこずを私たち党員が知っおいる理由の䞀郚である可胜性がありたす。䞀郚の人々が自分自身を玍埗させ始めるたでは、芏暡が小さすぎるので、結局問題はないかもしれたせん。 5行のサンプルではなく、実際のコヌディング経隓を信頌しおください

「゚ラヌを返す必芁があるずきに、䜕らかの圢でパニックを暗黙的に実行しおいるようです。」

暗黙的ではありたせん。 それは明癜です。 pop挔算子は、必芁な凊理を行うずきに䜿甚したす。 それがあなたが望むこずをしないずき、あなたはそれを䜿いたせん。 それが行うこずは、単䞀の単玔な文でキャプチャするのに十分単玔ですが、仕様はおそらくそのようなものがどのように機胜するかであるため、完党な段萜を取りたす。 暗黙的なものはありたせん。 さらに、リタヌンずたったく同じように、スタックの1぀のレベルを巻き戻すだけなので、パニックにはなりたせん。 それはリタヌンず同じくらいパニックですが、それはたったくありたせん。

popを次のように綎っおもかたいたせん。 たたは䜕でも。 個人的には、Goは珟圚シンボルが豊富な蚀語ではないため、単語はもう少しGoに䌌おいるず思いたすが、シンボルには既存の゜ヌスコヌドず競合しないずいう利点があるこずを吊定できたせん。 私は、セマンティクスず、それらに基づいお構築できるもの、および新しいセマンティクスが、スペリングよりも新しい経隓豊富なプログラマヌにどのような動䜜を提䟛するかに興味がありたす。

「延期もややコストのかかる操䜜であるため、゚ラヌが発生する可胜性のあるすべおの関数で延期をどのように䜿甚するかがわかりたせん。」

私はすでにそれを認めたした。 䞀般的にはそれほど高䟡ではないこずをお勧めしたすが、最適化の目的で、ホットな関数がある堎合は、珟圚の方法で蚘述しおください。 すべおの゚ラヌ凊理関数を100倉曎しようずするのは明らかに私の目暙ではありたせんが、それらの80をはるかに単玔で正確にし、20のケヌスおそらく正盎に蚀っお98/2のようにをそのたたにしおおくこずです。それは。 Goコヌドの倧郚分は、延期の䜿甚に敏感ではありたせん。これが、結局のずころ、 deferがそもそも存圚する理由です。

実際、deferを䜿甚しないようにプロポヌザルを簡単に倉曎し、 trapようなキヌワヌドを、衚瀺される堎所に関係なく1回だけ実行される宣蚀ずしお䜿甚できたす。これは、deferが実際にプッシュするステヌトメントである方法ではありたせん。遅延関数のスタックぞのハンドラヌ。 蚀語に新しい抂念を远加しないように、意図的にdeferを再利甚するこずを遞択したした...予期せず人々を噛むルヌプの延期から生じる可胜性のある眠を理解するこずさえできたす。 しかし、それでも理解できるのは1぀のdefer抂念にすぎたせん。

蚀語に新しいキヌワヌドを远加するこずは重倧な倉曎であるこずを明確にするためだけに。

package main

import (
    "fmt"
)

func return(i int)int{
    return i
}

func main() {
    return(1)
}

結果は

prog.go:7:6: syntax error: unexpected select, expecting name or (

぀たり、 try 、 trap 、 assert任意のキヌワヌドを蚀語に远加しようずするず、倧量のコヌドが砎損するリスクがありたす。 もはや維持されない可胜性のあるコヌド。

そのため、私は最初に、ステヌトメントのコンテキストで倉数に適甚できる特別な? go挔算子を远加するこずを提案したした。 珟圚の?文字は、倉数名の䞍正な文字ずしお指定されおいたす。 ぀たり、珟圚のGoコヌドでは珟圚䜿甚されおいないため、重倧な倉曎を加えるこずなく導入できたす。

割り圓おの巊偎でそれを䜿甚する際の問題は、Goが耇数の戻り匕数を蚱可するこずを考慮しおいないこずです。

たずえば、この関数に぀いお考えおみたす

func getCoord() x int, y int, z int, err error{
    x, err = getX()
    if err != nil{
        return 
    }

    y, err = getY()
    if err != nil{
        return 
    }

    z, err = getZ()
        if err != nil{
        return 
    }
    return
}

䜿甚する堎合 たたは、割り圓おのlhsを詊しお、if err= nilブロックを削陀したす。゚ラヌは、他のすべおの倀がゎミ箱になったこずを意味するず自動的に掚定したすか このようにしたらどうなるでしょう

func GetCoord() (x, y, z int, err error) {
    err = try GetX(&x) // or err? = GetX(&x) 
    err = try GetY(&y) // or err? = GetY(&x) 
    err = try GetZ(&z) // or err? = GetZ(&x) 
}

ここではどのような仮定をしたすか 䟡倀を捚おおも倧䞈倫だず思っおも害はないずいうこずですか ゚ラヌがより倚くの譊告であり、倀xが適切である堎合はどうなりたすか ゚ラヌをスロヌする唯䞀の関数がGetZの呌び出しであり、x、yの倀が実際に適切である堎合はどうなりたすか 私たちはそれらを返すず思いたすか 名前付きの戻り匕数を䜿甚しない堎合はどうなりたすか 戻り匕数がマップやチャネルなどの参照型である堎合はどうなりたすか呌び出し元にnilを返すのが安党であるず想定する必芁がありたすか

TLDR; 远加したすか たたは、削陀するために割り圓おにtry

if err != nil{
    return err
}

特兞よりも混乱が倚すぎたす。

そしお、 trap提案のようなものを远加するず、砎損の可胜性が生じたす。

そのため、別号で提案したした。 任意の型でfunc ?() boolを宣蚀できるようにしたので、

x, err := doSomething; return x, err?    

トラップの副䜜甚は、どのタむプにも圓おはたる方法で発生させるこずができたす。

そしおを適甚したす私が瀺したようにステヌトメントのみを凊理するこずで、ステヌトメントのプログラム可胜性が可胜になりたす。 私の提案では、誰かがキヌワヌド+であるケヌスを切り替えるこずができる特別なswitchステヌトメントを蚱可するこずを提案したす。

switch {
    case select?:
    //side effect/trap code specific to select
    case return?:
    //side effect/trap code specific to returns
    case for?: 
    //side effect/trap code specific to for? 

    //etc...
}  

䜿甚しおいる堎合は 明瀺的なものがないタむプでは 宣蚀された関数たたは組み蟌み型の堎合、var == nil ||かどうかをチェックするデフォルトの動䜜れロの倀{ステヌトメントを実行}は掚定される意図です。

Idk、プログラミング蚀語蚭蚈の専門家ではありたせんが、これではありたせん

たずえば、os.Chdir関数は珟圚

func Chdir(dir string) error {
  if e := syscall.Chdir(dir); e != nil {
      return &PathError{"chdir", dir, e}
  }
  return nil
}

この提案の䞋では、次のように曞くこずができたす

func Chdir(dir string) error {
  syscall.Chdir(dir) || &PathError{"chdir", dir, err}
  return nil
}

javascriptの矢印関数たたはDartが定矩する「倪い矢印構文」ず本質的に同じもの

䟋えば

func Chdir(dir string) error {
    syscall.Chdir(dir) => &PathError{"chdir", dir, err}
    return nil
}

ダヌツツアヌから。

匏を1぀だけ含む関数の堎合、簡略構文を䜿甚できたす。

bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
=> expr構文は、{returnexpr;の省略圢です。 }。 =>衚蚘は、倪い矢印構文ず呌ばれるこずもありたす。

@mortdeus 、ダヌツ矢印の巊偎は関数のシグネチャですが、 syscall.Chdir(dir)は匏です。 それらは倚かれ少なかれ無関係のようです。

@mortdeus先ほど明確にするのを忘れたしたが、ここでコメントしたアむデアは、あなたがタグ付けした提案ずほずんど䌌おいたせん。 プレヌスホルダヌずしお?のアむデアが奜きなので、それをコピヌしたしたが、私のアむデアは、 try...catchの既知の問題のいく぀かを回避しながら、゚ラヌを凊理するために単䞀のコヌドブロックを再利甚するこずを匷調したした。 新しいアむデアを提䟛できるように、これたで話されおいなかったものを思い぀くように现心の泚意を払いたした。

新しい条件付きreturn たたはreturnIf ステヌトメントはどうですか

return(bool expression) ...

すなわち。

err := syscall.Chdir(dir)
return(err != nil) &PathError{"chdir", dir, e}

a, b, err := Foo()    // signature: func Foo() (string, string, error)
return(err != nil) "", "", err

たたは、 fmtに、3぀ではなく1぀の行で1぀のラむナヌの戻り倀のみの関数をフォヌマットさせたす。

err := syscall.Chdir(dir)
if err != nil { return &PathError{"chdir", dir, e} }

a, b, err := Foo()    // signature: func Foo() (string, string, error)
if err != nil { return "", "", err }

名前付きパラメヌタヌず組み合わせるず、右端の゚ラヌがnilでない堎合に早期に戻る挔算子を远加するだけで、必芁なすべおを取埗できるこずがわかりたす。

func NewClient(...) (c *Client, err error) {
    defer annotateError(&err, "client couldn't be created")

    listener := net.Listen("tcp4", listenAddr)?
    defer closeOnErr(&err, listener)
    conn := ConnectionManager{}.connect(server, tlsConfig)?
    defer closeOnErr(&err, conn)

    if forwardPort == 0 {
        env, err := environment.GetRuntimeEnvironment()
        if err != nil {
            log.Printf("not forwarding because: %v", err)
        } else {
            forwardPort, err = env.PortToForward()
            if err != nil {
                log.Printf("env couldn't provide forward port: %v", err)
            }
        }
    }
    var forwardOut *forwarding.ForwardOut
    if forwardPort != 0 {
         forwardOut = forwarding.NewOut(pop url.Parse(fmt.Sprintf("http://127.0.0.1:%d", forwardPort)))
    }

    client := &Client{listener: listener, conn: conn, forward: forwardOut}

    toServer := communicationProtocol.Wrap(conn)
    toServer.Send(&client.serverConfig)?
    toServer.Send(&stprotocol.ClientProtocolAck{ClientVersion: Version})?
    session := communicationProtocol.FinalProtocol(conn)?
    client.session = session

    return client, nil
}

func closeOnErr(err *error, c io.Closer) {
    if *err != nil {
        closeErr := c.Close()
        if err != nil {
            *err = multierror.Append(*err, closeErr)
        }
    }
}

func annotateError(err *error, annotation string) {
    if *err != nil {
        log.Printf("%s: %v", annotation, *err)
        *err = errwrap.Wrapf(annotation +": {{err}}", err)
    }
}

珟圚、Goのコンセンサスに぀いおの私の理解は、名前付きパラメヌタヌに反しおいたすが、名前パラメヌタヌのアフォヌダンスが倉曎されるず、コンセンサスも倉曎されたす。 もちろん、コンセンサスがそれに察しお十分に匷い堎合は、アクセサヌを含めるオプションがありたす。

このアプロヌチにより、私が探しおいるもの関数の先頭で゚ラヌを䜓系的に凊理しやすくする、そのようなコヌドを因数分解する機胜、行数の削枛を、元の提案を含む他のほずんどの提案で埗るこずができたす。 。 たた、Goコミュニティが気に入らないず刀断した堎合でも、機胜ごずにコヌドに含たれおおり、どちらの方向にもむンピヌダンスの䞍䞀臎がないため、気にする必芁はありたせん。

眲名func GetInt() (x int, err error)関数をOtherFunc(GetInt()?, "...") たたは最終的な結果が䜕であれのコヌドで䜿甚できるようにする提案を、構成できないものよりも優先するこずを衚明したすが衚珟。 繰り返し発生する単玔な゚ラヌ凊理句の煩わしさは少なくなりたすが、最初の結果を埗るこずができるようにarity 2の関数をアンパックするコヌドの量は、䟝然ずしお厄介なほど倧きく、実際には䜕も远加されたせん。結果のコヌド。

@thejerf 、ここには奇劙な振る舞いがたくさんあるような気がしたす。 net.Listen呌び出しおいたす。これぱラヌを返したすが、割り圓おられおいたせん。 次に、延期しおerrを枡したす。 新しいdeferはそれぞれ最埌のものを䞊曞きしお、 annotateErrorが呌び出されないようにしたすか たたは、スタックしお、たずえばtoServer.Sendから゚ラヌが返された堎合、 closeOnErrが2回呌び出され、次にannotateErrorが呌び出されたすか closeOnErrは、前の呌び出しに䞀臎する眲名がある堎合にのみ呌び出されたすか この堎合はどうですか

conn := ConnectionManager{}.connect(server, tlsConfig)?
fmt.Printf("Attempted to connect to server %#v", server)
defer closeOnErr(&err, conn)

コヌドを読んでいるず、混乱したす。たずえば、なぜ私はただ蚀うこずができないのかなどです。

client.session = communicationProtocol.FinalProtocol(conn)?

おそらく、 FinalProtocolが゚ラヌを返しおいるためですか しかし、それは読者には隠されおいたす。

最埌に、゚ラヌを報告しお関数内で゚ラヌから回埩したい堎合はどうなりたすか あなたの䟋はそのケヌスを防ぐように思われたすか

_補遺_

OK、゚ラヌから回埩したいずきは、䟋ずしお、次のように割り圓おたす。

env, err := environment.GetRuntimeEnvironment()

゚ラヌがシャドりされおいるので問題ありたせんが、倉曎した堎合は...

forwardPort, err = env.PortToForward()
if err != nil {
    log.Printf("env couldn't provide forward port: %v", err)
}

ただ

forwardPort = env.PortToForward()

次に、スコヌプ内で䜜成されたerrを䜿甚しおいるため、凊理された遅延゚ラヌはそれをキャッチしたせん。 それずも私は䜕かが足りないのですか

関数が倱敗する可胜性があるこずを瀺す構文ぞの远加は、良いスタヌトだず思いたす。 私はこれらの線に沿っお䜕かを提案したす

func (r Reader) Read(b []byte) (n int) fails {
    if somethingFailed {
        fail errors.New("something failed")
    }

    return 0
}

関数が倱敗した堎合 return代わりにfailキヌワヌドを䜿甚しお、各戻りパラメヌタヌのれロ倀を返したす。

func (c EmailClient) SendEmail(to, content string) fails {
    if !c.connected() {
        fail errors.New("could not connect")
    }

    // You can handle it and execution will continue if you don't fail or return
    n := r.Read(b) handle (err) {
        fmt.Printf("failed to read: %s", err)
    }

    // This shouldn't compile and should complain about an unhandled error
    n := r.Read(b)
}

このアプロヌチには、珟圚のコヌドを機胜させるず同時に、少なくずも構文では゚ラヌ凊理を改善するための新しいメカニズムを有効にするずいう利点がありたす。

キヌワヌドぞのコメント

  • failsは最良の遞択肢ではないかもしれたせんが、珟圚私が考えるこずができる最良の遞択肢です。 err たたはerrs を䜿甚するこずを考えたしたが、珟圚の䜿甚方法により、珟圚の期埅から悪い遞択になる可胜性がありたす errは倉数名である可胜性が高いです。 errsは、スラむス、配列、たたぱラヌず芋なされる堎合がありたす。
  • handleは少し誀解を招く可胜性がありたす。 recoverを䜿甚したかったのですが、 panic䜿甚されおいたす...

線集 io.Reader.Read()に䞀臎するようにr.Read呌び出しを倉曎したした。

その提案の理由の䞀郚は、Goの珟圚のアプロヌチは、返されたerror倀が関数の倱敗を瀺しおいるのか、関数の䞀郚ずしお゚ラヌ倀を返しおいるのか github.com/pkg/errorsをツヌルが理解するのに圹立たないためです。

関数が倱敗を明瀺的に衚珟できるようにするこずが、゚ラヌ凊理を改善するための最初のステップだず思いたす。

@ibrasho 、あなたはどのように䟋が違うのですか...

func (c EmailClient) SendEmail(to, content string) error {
    // ...

    // You can handle it and execution will continue if you don't fail or return
    _, _, err := r.Read()
        if err != nil {
        fmt.Printf("failed to read: %s", err)
    }

    // This shouldn't compile and should complain about an unhandled error
    _, _, err := r.Read()
}

... error未凊理のむンスタンスに察しおコンパむラの譊告たたはlintを䞎える堎合はどうなりたすか 蚀語の倉曎は必芁ありたせん。

2぀のこず

  • 提案された構文は読みやすく、芋栄えも良いず思いたす。 😁
  • 私のバヌゞョンでは、関数に明瀺的に倱敗したこずを瀺す機胜を䞎える必芁がありたす。 これは珟圚Goに欠けおいるものであり、ツヌルがより倚くのこずを実行できるようにする可胜性がありたす。 error倀を返す関数はい぀でも倱敗ずしお扱うこずができたすが、それは前提条件です。 関数が2぀のerror倀を返す堎合はどうなりたすか

私の提案には、私が削陀したものがありたした。それは自動䌝播でした。

func (c EmailClient) SendEmail(to, content string) fails {
    n := r.Read(b)

    // Would automaticaly propgate the error, so it will be equivlent to this:
    // n := r.Read(b) handle (err) {
    //  fail err
    // }
}

゚ラヌ凊理は明瀺的である必芁があるず思うので、それを削陀したした。

線集 io.Reader.Read()に䞀臎するようにr.Read呌び出しを倉曎したした。

それで、これは有効な眲名たたはプロトタむプになりたすか

func (r *MyFileReader) Read(b []byte) (n int, err error) fails

 io.Reader実装では、読み取るものがなくなった堎合や障害状態に関するその他の゚ラヌが発生した堎合に、 io.EOF割り圓おられたす。

はい。 しかし、 errがその仕事をしおいる関数の倱敗を瀺すこずを期埅するべきではありたせん。 読み取り倱敗゚ラヌは、ハンドルブロックに枡す必芁がありたす。 ゚ラヌはGoの倀であり、この関数によっお返される゚ラヌは、この関数が返すものである以倖に特別な意味を持぀べきではありたせん䜕らかの奇劙な理由で。

私は、倱敗するず戻り倀がれロ倀ずしお返されるこずになるず提案しおいたした。 珟圚のReader.Readは、この新しいアプロヌチでは䞍可胜な可胜性のあるいく぀かの玄束をすでに行っおいたす。

n> 0バむトの読み取りに成功した埌、Readで゚ラヌたたはファむルの終わりの状態が発生するず、読み取られたバむト数が返されたす。 同じ呌び出しからnil以倖の゚ラヌを返すか、埌続の呌び出しから゚ラヌおよびn == 0を返す堎合がありたす。 この䞀般的なケヌスの䟋は、入力ストリヌムの最埌にれロ以倖のバむト数を返すリヌダヌがerr == EOFたたはerr == nilのいずれかを返す堎合がありたす。 次の読み取りは0、EOFを返す必芁がありたす。

呌び出し元は、゚ラヌ゚ラヌを考慮する前に、返されたn> 0バむトを垞に凊理する必芁がありたす。 そうするこずで、いく぀かのバむトを読み取った埌に発生するI / O゚ラヌず、蚱可されおいる䞡方のEOF動䜜を正しく凊理できたす。

Readの実装は、lenp== 0の堎合を陀いお、nil゚ラヌでれロバむトカりントを返すこずをお勧めしたせん。呌び出し元は、0ずnilの戻りを䜕も起こらなかったこずを瀺すものずしお扱う必芁がありたす。 特に、EOFを瀺すものではありたせん。

珟圚提案されおいるアプロヌチでは、この動䜜のすべおが可胜ずいうわけではありたせん。 珟圚の読み取りむンタヌフェむスコントラクトから、郚分的な読み取りの凊理方法など、いく぀かの欠点がありたす。

䞀般に、関数が倱敗するたでに郚分的に実行された堎合、関数はどのように動䜜する必芁がありたすか 正盎、ただ考えおいたせんでした。

io.EOFの堎合は単玔です。

func DoSomething(r io.Reader) fails {
    // I'm using rerr so that I don't shadow the err returned from the function
    n, err := r.Read(b) handle (rerr) {
        if rerr != io.EOF {
            fail err
        }
        // Else do nothing?
    }
}

@thejerf 、ここには奇劙な振る舞いがたくさんあるような気がしたす。 ゚ラヌを返すnet.Listenを呌び出しおいたすが、割り圓おられおいたせん。

゚ラヌがnilでない堎合、他の倀に察しおれロ倀で゚ラヌを返すこずを瀺すために、耇数の人によっお提案された䞀般的な?挔算子を䜿甚しおいたす。 Goは挔算子を倚甚する蚀語ではないず思うので、挔算子よりも短い単語の方が少し奜きですが、 ?がその蚀語に入る堎合でも、足を螏み入れるのではなく、賞金を数えたす。ハフ。

新しい延期はそれぞれ最埌の延期を䞊曞きするので、annotateErrorは呌び出されたせんか たたは、それらはスタックするので、たずえばtoServer.Sendから゚ラヌが返された堎合、closeOnErrが2回呌び出され、次にannotateErrorが呌び出されたすか

これはdeferず同じように機胜したす https 

玛らわしいかもしれない1぀の偎面は、珟圚のGoでは、名前付きパラメヌタヌが「実際に返されるものは䜕でも」になるずいうこずです。そのため、私が行ったこずを実行し、ポむンタヌを取埗しお枡すこずができたす。 return errors.New(...)ような倀を盎接返すかどうかに関係なく、それを遅延関数に適甚しお操䜜したす。これは、名前付き倉数ではない「新しい倉数」のように盎感的に芋えるかもしれたせんが、実際にはGoになりたす。延期が実行されるたでに、名前付き倉数に割り圓おられたす。 珟圚のGoのこの特定の詳现を今すぐ無芖するのは簡単です。 今は混乱するかもしれたせんが、このむディオムを䜿甚したコヌドベヌスでさえ䜜業した堎合぀たり、これが「ベストプラクティスに移行」する必芁があるず蚀っおいるわけではありたせんが、ほんの数回の露出で十分です、 dそれをかなり早く理解したす。 なぜなら、もう䞀床明確にするために、提案された倉曎ではなく、Goがすでに機胜しおいる方法です。

これは、これたで提案されおいなかったず思う提案です。 䟋を䜿甚しお

 r, !handleError := something()

これの意味はこれず同じです

 r, _xyzzy := something()
 if ok, R := handleError(_xyzzy); !ok { return R }

ここで、 _xyzzyは、スコヌプがこれらの2行のコヌドにのみ拡匵される新しい倉数であり、 Rは耇数の倀である可胜性がありたす。

この提案の利点は、゚ラヌに固有のものではなく、れロ倀を特別に凊理せず、特定のコヌドブロック内で゚ラヌをラップする方法を簡朔に指定するのが簡単です。 構文の倉曎はわずかです。 簡単な翻蚳を考えるず、この機胜がどのように機胜するかを理解するのは簡単です。

欠点は、暗黙的な戻り倀が導入されるこず、゚ラヌを返すだけのゞェネリックハンドラヌを蚘述できないこず、戻り倀は呌び出し元の関数に基づく必芁があるため、ハンドラヌに枡される倀が呌び出し元のコヌドでは䜿甚できたせん。

䜿甚方法は次のずおりです。

func Read(filename string) error {
  herr := func(err error) (bool, error) {
      if err != nil { return true, fmt.Errorf("Read failed: %s", err) }
      return false, nil
  }

  f, !herr := OpenFile(filename)
  b, !herr := ReadBytes(f)
  !herr := ProcessBytes(b)
  return nil
}

たたは、初期化コヌドが倱敗した堎合にt.Fatalを呌び出すためのテストで䜿甚するこずもできたす。

func TestSomething(t *testing.T) {
  must := func(err error) bool { t.Fatalf("init code failed: %s", err); return true }
  !must := setupTest()
  !must := clearDatabase()
  ...
}

関数のシグネチャをfunc(error) errorだけに倉曎するこずをお勧めしたす。 これにより、倧倚数のケヌスが単玔化され、゚ラヌをさらに分析する必芁がある堎合は、珟圚のメカニズムを䜿甚するだけです。

構文の質問関数をむンラむンで定矩できたすか

func Read(filename string) error {
    f, !func(err error) error {
        if err != nil { return true, fmt.Errorf("... %s", err) }
        return false, nil
    } := OpenFile(filename)
    /...

私は「そうしないでください」に慣れおいたすが、構文によっお、特殊なケヌスの数を枛らすこずができるはずです。 これにより、次のこずも可胜になりたす。

func failed(s string) func(error) error {
    return func(err error) {
       // returns a decorated error with the given string
   }
}

func Read(filename string) error {
  f, !failed("couldn't open file") := OpenFile(filename)
  b, !failed("couldn't read file") := ReadBytes(f)
  !failed("couldn't process file") := ProcessBytes(b)
  return nil
}

これは、少なくずもそのようなものを簡朔に取り蟌むずいう点で、その皮のこずに察するより良い提案の1぀ずしお私を驚かせたす。 これは、この時点で䟋倖ベヌスのコヌドよりも優れた゚ラヌを出力しおいるIMHOの別のケヌスです。䟋倖を䌝播させるのは非垞に簡単であるため、゚ラヌの性質に関する詳现を取埗できないこずがよくありたす。

たた、パフォヌマンス䞊の理由から、バング゚ラヌ関数はれロ倀で呌び出されないものずしお定矩するこずをお勧めしたす。 これにより、パフォヌマンスぞの圱響を最小限に抑えるこずができたす。 先ほど瀺した堎合、読み取りが正垞に成功した堎合、すべおの゚ラヌですでにif発生し、 if句が倱敗しおいる珟圚の読み取り実装よりもコストがかかりたせん。 垞にnil関数を呌び出しおいる堎合、むンラむン化できない堎合は垞に非垞に高額になり、時間の無駄になるこずはありたせん。 ゚ラヌがアクティブに発生しおいる堎合は、ほずんどすべおの状況で関数呌び出しを正圓化しお䜙裕を持たせるこずができたす珟圚のメ゜ッドにフォヌルバックできない堎合が、゚ラヌが発生しない堎合は実際には必芁ありたせん。たた、bang関数は、実装時にれロ以倖の倀を想定できるこずを意味したす。これにより、関数も単玔化されたす。

@thejerf玠敵ですが、幞せな道は倧きく倉わりたした。
倚くのメッセヌゞの前に、「たたは」sintaxのようなRubyを䜿甚するずいう提案がありたした- f := OpenFile(filename) or failed("couldn't open file") 。

远加の懞念事項-それは、任意のタむプのパラメヌタの堎合ですか、それずも゚ラヌの堎合のみですか ゚ラヌの堎合のみ-タむプ゚ラヌはコンパむラにずっお特別な意味を持぀必芁がありたす。

@thejerf玠敵ですが、幞せな道は倧きく倉わりたした。

ポヌルハンキンの元の提案のように芋える元の提案のおそらく䞀般的なパスを区別するこずをお勧めしたす。

func Read(filename string) error {
  herr := func(err error) (bool, error) {
      if err != nil { return true, fmt.Errorf("Read failed: %s", err) }
      return false, nil
  }

  f, !herr := OpenFile(filename)
  b, !herr := ReadBytes(f)
  !herr := ProcessBytes(b)
  return nil
}

おそらくherrどこかで考慮されおいお、それを完党に特定するために䜕が必芁かを探求するこずは、この䌚話の必芁性であり、私自身の個人的なコヌドでそれをどのように䜿甚するかに぀いおの私自身の考えです。これは、提案によっお他に䜕が可胜になり、提䟛されるかを探求するだけです。 関数を文字通りむンラむン化するこずはおそらく悪い考えだずすでに蚀いたしたが、文法はおそらく文法を単玔に保぀こずを可胜にするはずです。 私はすでに3぀の関数を受け取るGo関数を蚘述し、それらすべおを呌び出しにむンラむン化するこずができたす。 これは、Goが壊れおいる、たたはGoがそれを防ぐために䜕かをする必芁があるずいう意味ではありたせん。 コヌドの明快さを重芖するなら、そうすべきではないずいうこずです。 Goがコヌドを明確にするのが奜きですが、コヌドを明確に保぀ために開発者には䟝然ずしおある皋床の責任がありたす。

あなたが私にその「幞せな道」を蚀う぀もりなら

func Read(filename string) error {
  f, !failed("couldn't open file") := OpenFile(filename)
  b, !failed("couldn't read file") := ReadBytes(f)
  !failed("couldn't process file") := ProcessBytes(b)
  return nil
}

がらくたで読みにくいですが、幞せな道は読みやすいです

func Read(filename string) error {
  f, err := OpenFile(filename)
  if err != nil {
    return fmt.Errorf("Read failed: %s", err)
  }

  b, err := ReadBytes(f)
  if err != nil {
    return fmt.Errorf("Read failed: %s", err)
  }

  err = ProcessBytes(b)
  if err != nil {
    return fmt.Errorf("Read failed: %s", err)
  }

  return nil
}

それから私は2番目が読みやすい唯䞀の可胜な方法を提出したす。それはあなたがすでにそれを読むこずに慣れおいお、あなたの目が幞せな道を芋るために正確に正しい道をスキップするように蚓緎されおいるずいうこずです。 私もそうなので、私はそれを掚枬するこずができたす。 ただし、別の構文に慣れたら、そのためのトレヌニングも受けられたす。 構文は、珟圚の感じ方ではなく、すでに慣れおいるずきの感じ方に基づいお分析する必芁がありたす。

たた、2番目の䟋で远加された改行は、実際のコヌドに䜕が起こるかを衚しおいるこずにも泚意しおください。 珟圚のGo゚ラヌ凊理がコヌドに远加する傟向があるのはコヌドの「行」だけではなく、それ以倖の堎合は非垞に単玔な関数であるはずのコヌドに倚くの「段萜」を远加したす。 ファむルを開いお、いく぀かのバむトを読み取り、それらを凊理したいず思いたす。 したくない

ファむルを開きたす。

そしお、それでよければ、いく぀かのバむトを読み取りたす。

そしお、それでよければ、それらを凊理したす。

慣れお流暢に䜿うず、実際のコヌドでどのように機胜するかを実際に分析するのではなく、「これは私が慣れおいるものではない」ずいう反察祚がたくさんあるように感じたす。 。

returnステヌトメントを非衚瀺にするずいうアむデアは奜きではありたせん。

f := OpenFile(filename) or return failed("couldn't open file")
....
func failed(msg string, err error) error { ... } 

この堎合、 orはれロ条件付き転送挔算子です。
れロ以倖の堎合は、最埌のリタヌンを転送したす。
挔算子?>を䜿甚したCにも同様の提案がありたす

f := OpenFile(filename) ?> return failed("couldn't open file")

@thejerf "happy path"は、failed...の呌び出しが前に

「shift」キヌで入力された@rodcorsi文字は悪い

この方法を珟圚よりも耇雑にしないでください。 同じコヌドを3぀以䞊ではなく1行で実際に移動するこずは、実際には解決策ではありたせん。 私は個人的に、これらの提案のどれもそれほど実行可胜であるずは思いたせん。 みんな、数孊はずおも簡単です。 「Try-catch」のアむデアを採甚するか、珟圚の状態を維持したす。これは、倚くの「if then else」ずコヌドノむズを意味し、FluentInterfaceのようなOOパタヌンでの䜿甚にはあたり適しおいたせん。

すべおのハンドダりンずおそらくいく぀かのハンドアップをありがずうございたした;-冗談です

@KamyarM IMO、「最もよく知られおいる代替手段を䜿甚するか、たったく倉曎を加えない」ずいうのは、あたり生産的な発蚀ではありたせん。 それはむノベヌションを止め、埪環論法を促進したす。

@KernelDeimos私はあなたに同意したすが、このスレッドには、正確な4 5行を1行に移動するずいう叀いものを本質的に支持しおいた倚くのコメントがありたすが、これは実際の解決策ずは芋なされたせん。詊しおみおください-他の意芋のためにドアを閉めるキャッチ。 個人的には、このtry-catchの抂念を発明した人は本圓に考えおいたず思いたす。欠陥はほずんどないかもしれたせんが、それらの欠陥はプログラミングの習慣が悪いために発生したものであり、削陀たたは制限しおも、プログラマヌに適切なコヌドを蚘述させる方法はありたせん。プログラミング蚀語が持぀かもしれないすべおの良いたたはいく぀かは悪い機胜を蚀うかもしれたせん。
私は以前にこのようなものを提案したしたが、これは正確にはjavaたたはCのtry-catchではなく、珟圚の゚ラヌ凊理ずラむブラリをサポヌトできるず思いたす。䞊蚘の䟋の1぀を䜿甚したす。 したがっお、基本的にコンパむラは各行の埌に゚ラヌをチェックし、err倀がnil以倖に蚭定されおいる堎合はcatchブロックにゞャンプしたす。

try (var err error){ 
    f, err := OpenFile(filename)
    b, err := ReadBytes(f)
    err = ProcessBytes(b)
    return nil
} catch (err error){ //Required
   return err
} finally{ // Optional
    // Do something else like close the file or connection to DB. Not necessary in this example since we  return earlier.
}

@KamyarM
あなたの䟋では、コヌドを曞いおいる時点でどのメ゜ッドが゚ラヌを返したかをどうやっお知るこずができたすか ゚ラヌを凊理する3番目の方法「远加のコンテキスト情報ずずもに゚ラヌを返す」を実行するにはどうすればよいですか

@urandom
1぀の方法は、Goスむッチを䜿甚しお、キャッチで䟋倖のタむプを芋぀けるこずです。 そのようにOpenFileが原因であるこずがわかっおいるpathError䟋倖があるずしたす。 GoLangでのerr= nil゚ラヌ凊理の堎合、珟圚ずそれほど倉わらない別の方法は次のずおりです。

try (var err error){ 
    f, err := OpenFile(filename)
} catch (err error){ //Required
   return err
}
try (var err error){ 
    b, err := ReadBytes(f)
catch (err error){ //Required
   return err
}
try (var err error){ 
    err = ProcessBytes(b)
catch (err error){ //Required
   return err
}
return nil

したがっお、この方法でオプションがありたすが、制限はありたせん。 どの行が問題を匕き起こしたかを本圓に知りたい堎合は、今のように倚くのif-then-elsesを曞くのず同じ方法で、すべおの行をtrycatchに入れたす。 ゚ラヌがあなたにずっお重芁ではなく、このスレッドで説明されおいる䟋で実際にそれに぀いおである呌び出し元メ゜ッドにそれを枡したい堎合、私は提案されたコヌドがちょうど仕事をしおいるず思いたす。

@KamyarMあなたが今どこから来おいるのかわかりたす。 try ... catchに反察する人がたくさんいるずしたら、try ... catchは完璧ではなく、欠点があるずいう蚌拠だず思いたす。 これは問題の簡単な解決策ですが、Go2が他の蚀語で芋たものよりも゚ラヌ凊理を改善できるのであれば、それは本圓に玠晎らしいこずだず思いたす。

先ほど提案したtry ... catchの悪いずころをずらなくおも、try ... catchの良いずころをずるこずは可胜だず思いたす。 3行を1行たたは2行に倉えおも䜕も解決しないこずに同意したす。

私が芋おいるように、根本的な問題は、ロゞックの䞀郚が「呌び出し元に戻る」堎合、関数内の゚ラヌ凊理コヌドが繰り返されるこずです。 い぀でもロゞックを倉曎したい堎合は、 if err != nil { return nil }すべおのむンスタンスを倉曎する必芁がありたす。

そうは蚀っおも、関数が暗黙的に䜕もthrowできない限り、私はtry...catchのアむデアが本圓に奜きです。

catch {}のロゞックで、制埡フロヌを䞭断するためにbreakキヌワヌドが必芁な堎合は、もう1぀䟿利だず思いたす。 制埡フロヌを壊さずに゚ラヌを凊理したい堎合がありたす。 䟋「これらのデヌタの各項目に察しお䜕かを実行し、リストにnil以倖の゚ラヌを远加しお続行したす」

@KernelDeimos私は

try..catchを䜿甚するよりも「たたはreturn」を19642、21498ずブレンドしたいdefer / panic / restoreはすでに存圚したす。同じ関数内でスロヌするこずは、耇数のgotoステヌトメントを持っおいるようなもので、catch内にタむプスむッチを远加するず面倒になりたす。 try..catchをスタックの䞊䜍に配眮するこずで、゚ラヌ凊理を忘れるこずができたすたたは、スコヌプが単䞀関数内でtry..catchを実行する堎合は、コンパむラヌを倧幅に耇雑にしたす

@egorse
@KamyarMが瀺唆しおいるtry-catch構文は、䟋倖の玹介ではなく、゚ラヌ戻り倉数を凊理するための構文シュガヌであるようです。 私はさたざたな理由で「たたはreturn」タむプの構文を奜みたすが、それは正圓な提案のようです。

そうは蚀っおも、 @ KamyarM 、なぜtry倉数定矩郚分があるのですか err倉数を定矩しおいたすが、ブロック自䜓内の他のerr倉数によっおシャドりされおいたす。 その目的は䜕ですか

errorタむプから切り離すこずができるように、監芖する倉数を指定するこずだず思いたす。 人々が本圓に泚意する必芁がない限り、シャドりむングルヌルを倉曎する必芁があるでしょう。 ただし、 catchブロックでの宣蚀に぀いおはよくわかりたせん。

@DeedleFakeはそれの目的がある蚀及たさに@egorse。 これは、tryブロックがそのオブゞェクトを監芖しおいるこずを意味したす。 たた、その範囲を制限したす。 これは、Cのusingステヌトメントに䌌おいたす。 Cでは、キヌワヌドを䜿甚しお定矩されたオブゞェクトは、そのブロックが実行されるず自動的に砎棄され、それらのオブゞェクトのスコヌプは「Using」ブロックに制限されたす。
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement

プログラマヌに゚ラヌを正しく凊理する方法を決定させたいので、catchを䜿甚する必芁がありたす。 CおよびJavaでは、catchも必須です。 Cでは、䟋倖を凊理したくない堎合は、その関数でtry-catchをたったく䜿甚したせん。 䟋倖が発生するず、呌び出し階局内の任意のメ゜ッドが䟋倖を凊理したり、再スロヌたたは別の䟋倖でラップしたりするこずができたす。 Javaでも同じこずができるずは思いたせん。 Javaでは、䟋倖をスロヌする可胜性のあるメ゜ッドは、関数シグネチャでそれを宣蚀する必芁がありたす。

このtry-catchブロックは正確なものではないこずを匷調したいず思いたす。 これらのキヌワヌドを䜿甚したのは、これが達成したいこずず類䌌しおおり、倚くのプログラマヌが粟通しおおり、ほずんどのプログラミング抂念コヌスで教えられおいるためです。

次のように、_名前付き゚ラヌリタヌンパラメヌタ_がある堎合にのみ機胜する_゚ラヌ時のリタヌン_割り圓おが存圚する可胜性がありたす。

func process(someInput string) (someOutput string, err error) {
    err ?= otherAction()
    return
}

errがnil堎合は、戻りたす。

Rustにtry砂糖を远加するずいうこの議論は、この議論の参加者に光を圓おるず思いたす。

FWIW、゚ラヌ凊理を単玔化するこずに関する叀い考えこれがナンセンスである堎合は謝眪

キャレット蚘号^で瀺されるレむズ識別子は、代入の巊偎にあるオペランドの1぀ずしお䜿甚できたす。 割り圓おの目的で、raise識別子は、倀に名前があるかどうかに関係なく、含たれおいる関数の最埌の戻り倀の゚むリアスです。 割り圓おが完了するず、関数は最埌の戻り倀をその型のれロ倀nil、0、false、 ""に察しおテストしたす。 れロず芋なされる堎合、関数は実行を継続し、そうでない堎合は戻りたす。

レむズ識別子の䞻な目的は、これが発生しおいるずいう事実を隠すこずなく、呌び出された関数からの゚ラヌを特定のコンテキストで呌び出し元に簡朔に䌝播するこずです。

䟋ずしお、次のコヌドに぀いお考えおみたす。

func Alpha() (string, error) {

    b, ^ := beta()
    g, ^ := gamma()
    return b + g, nil
}

これは、おおよそ次のものず同等です。

func Alpha() (ret1 string, ret2 error) {

    b, ret2 := beta()
    if ret2 != nil {
        return
    }

    g, ret2 := gamma()
    if ret2 != nil {
        return
    }

    return b + g, nil
}

次の堎合、プログラムの圢匏が正しくありたせん。

  • 昇絊識別子は、割り圓おで耇数回䜿甚されたす
  • 関数は倀を返したせん
  • 最埌の戻り倀のタむプには、れロに察する意味のある効率的なテストがありたせん

この提案は、その䟡倀があるものに぀いお、より倚くのコンテキスト情報を提䟛するずいう問題に察凊しおいないずいう点で他の提案ず䌌おいたす。

@gboyleそのため、IMOの最埌の戻り倀には、 errorずいう名前を付ける必芁がありたす。 これには2぀の重芁な意味がありたす。

1-他の戻り倀にも名前が付けられおいるため、
2-それらはすでに意味のあるれロ倀を持っおいたす。

@ object88 contextパッケヌゞの履歎が瀺すように、これには、組み蟌みのerrorタむプ通垞のGo error を定矩するなど、コアチヌムからのアクションが必芁です。いく぀かの䞀般的な属性メッセヌゞコヌルスタックなどを䜿甚したす。

AFAIKには、Goにはコンテキスト蚀語の構成芁玠はあたりありたせん。 goずdefer以倖に他のものはなく、これら2぀でさえ非垞に明確で明確です構文のボット-そしお目には-そしおセマ​​ンティクス。

このようなものはどうですか

私が取り組んでいる実際のコヌドをコピヌしたした

func (g *Generator) GenerateDevices(w io.Writer) error {
    var err error
    catch err {
        _, err = io.WriteString(w, "package cc\n\nconst (") // if err != nil { goto Caught }
        for _, bd := range g.zwClasses.BasicDevices {
            _, err = w.Write([]byte{'\t'}) // if err != nil { goto Caught }
            _, err = io.WriteString(w, toGoName(bd.Name)) // if err != nil { goto Caught }
            _, err = io.WriteString(w, " BasicDeviceType = ") // if err != nil { goto Caught }
            _, err = io.WriteString(w, bd.Key) // if err != nil { goto Caught }
            _, err = w.Write([]byte{'\n'}) // if err != nil { goto Caught }
        }
        _, err = io.WriteString(w, ")\n\nvar BasicDeviceTypeNames = map[BasicDeviceType]string{\n") // if err != nil { goto Caught }
       // ...snip
    }
    // Caught:
    return err
}

errがnil以倖の堎合、「catch」ステヌトメントの最埌たで壊れたす。 「catch」を䜿甚しお、通垞は同じタむプの゚ラヌを返す類䌌の呌び出しをグルヌプ化できたす。 呌び出しが関連しおいなくおも、埌で゚ラヌタむプを確認しお、適切にラップするこずができたす。

@lukescottは、 読んでいたすhttps://blog.golang.org/errors-are-values

@davecheneyキャッチのアむデア詊行なしは、その感情の粟神を維持したす。 ゚ラヌを倀ずしお扱いたす。 倀がnilでなくなるず、同じ関数内で単に壊れたす。 プログラムがクラッシュするこずはありたせん。

@lukescott今日はRobのテクニックを䜿甚できたす。蚀語を倉曎する必芁はありたせん。

䟋倖ず゚ラヌの間にはかなり倧きな違いがありたす。

  • ゚ラヌが予想されたすそれらのテストを䜜成できたす、
  • 䟋倖は予期されおいたせんしたがっお「䟋倖」、

倚くの蚀語は䞡方を䟋倖ずしお扱いたす。

ゞェネリックスずより良い゚ラヌ凊理の間で、Goのほずんどのコヌドクラッタヌぱラヌ凊理から来るので、私はより良い゚ラヌ凊理を遞択したす。 この皮の冗長性は優れおおり、単玔さを優先しおいるず蚀えたすが、IMOは、ワヌクフロヌの「ハッピヌパス」をあいたいなレベルたで芆い隠したす。

@thejerfからの提案を発展させたいず思いたす。

たず、 !代わりに、 or挔算子が導入されたす。この挔算子は、巊偎の関数呌び出しから最埌に返された匕数であり、右偎のreturnステヌトメントを呌び出したす。シフトされた匕数がれロ以倖゚ラヌタむプの堎合はnill以倖の堎合に呌び出される関数で、その匕数を枡したす。 ゚ラヌタむプのみを察象ずすべきだず人々が考える堎合は問題ありたせんが、この構造は、最埌の匕数ずしおブヌル倀を返す関数にも圹立぀ず思いたすこれは問題ありたせん。

Readメ゜ッドは次のようになりたす。

func Read(filename string) error {
  f := OpenFile(filename) or return errors.Contextf("opening file %s", filename)
  b := ReadBytes(f) or return errors.Contextf("reading file %s", filename)
  ProcessBytes(b) or return errors.Context("processing data")
  return nil
}

゚ラヌパッケヌゞは次のような䟿利な機胜を提䟛するず思いたす。

func Noop() func(error) error {
   return func(err error) {
       return err   
   }
}


func Context(msg string) func(error) error {
    return func(err error) {
        return fmt.Errorf("%s: %v", msg, err)
    }
}
...

これは、必芁なすべおのポむントをカバヌしながら、完党に読みやすいように芋えたす。たた、returnステヌトメントに粟通しおいるため、あたり異質に芋えたせん。

@urandomこのステヌトメントではf := OpenFile(filename) or return errors.Contextf("opening file %s", filename)理由をどのように知るこずができたすか たずえば、読み取り暩限がないのでしょうか、それずもファむルがたったく存圚しないのでしょうか。

@ dc0d
䞊蚘の䟋でも、ナヌザヌが指定したメッセヌゞはコンテキストが远加されただけなので、元の゚ラヌが含たれおいたす。 前述のように、元の提案から掟生したように、 or returnは、シフトされたタむプの単䞀のパラメヌタヌを受け取る関数を期埅したす。 これは重芁であり、非垞に倚くの人に適したナヌティリティ関数だけでなく、特定の倀の実際のカスタム凊理が必芁な堎合は、ほずんど独自の関数を䜜成できたす。

@urandomIMOそれはあたりにも隠したす。

ここでの私の2セント、私は簡単なルヌルを提案したいず思いたす

「関数の暗黙の結果゚ラヌパラメヌタ」

どの関数でも、結果パラメヌタヌリストの最埌に゚ラヌパラメヌタヌが含たれたす。
明瀺的に定矩されおいない堎合。

説明のために、次のように定矩された関数があるず仮定したす。

func fint{}
これは次ず同じですfunc fint、error{}
暗黙の結果゚ラヌルヌルに埓いたす。

割り圓おの堎合、次のように、バブルアップ、無芖、たたぱラヌをキャッチできたす。

1バブルアップ

x= f

fが゚ラヌを返す堎合、珟圚の関数はすぐに゚ラヌを返したす
たたは新しい゚ラヌスタックを䜜成したすか
珟圚の機胜がメむンの堎合、プログラムは停止したす。

これは、次のコヌドスニペットず同等です。

x、err= f
err= nil {の堎合
戻る...、゚ラヌ
}

2無芖する

x、_= f

゚ラヌの砎棄を明瀺的に通知するための、代入匏リストの最埌にある空癜の識別子。

3キャッチ

x、err= f

゚ラヌは通垞どおりに凊理する必芁がありたす。

この慣甚的なコヌド芏則の倉曎は、コンパむラヌで最小限の倉曎のみを必芁ずするはずだず私は信じおいたす
たたはプリプロセッサがその仕事をするはずです。

@ dc0dそれが䜕を隠しおいるのか、そしおどのように隠しおいるのか、䟋を挙げおいただけたすか

@urandom以前のコメントで尋ねたように、「元の゚ラヌはどこにありたすか」ずいう質問を匕き起こしたのはそのためです。 ゚ラヌを暗黙的に枡したすが、たずえばこの行の元の゚ラヌがどこにあるかは明確ではありたせん f := OpenFile(filename) or return errors.Contextf("opening file %s", filename) 。 OpenFile()によっお返された元の゚ラヌ-これは、「ファむル名に問題がある」だけでなく、読み取り暩限の欠劂やファむルの欠劂などの可胜性がありたす。

@ dc0d
同意したせん。 これは、http.Handlersを凊理するのずほが同じくらい明確です。埌で、それらをマルチプレクサに枡し、突然、芁求ず応答のラむタヌを取埗したす。 そしお、人々はこの皮の行動に慣れおいたす。 goステヌトメントが䜕をするのかを人々はどうやっお知るのでしょうか それは最初の出䌚いでは明らかに明確ではありたせんが、それでもかなり普及しおいお、蚀語で曞かれおいたす。

ほずんどの人に圓おはたるので、その新しい提案や、それがどのように機胜するのか誰にもわからないずいう理由で、私たちはいかなる提案にも反察すべきではないず思いたす。

@urandomこれでもう少し意味がありたす http.Handler䟋を含む。

そしお、私たちは物事に぀いお話し合っおいたす。 私は特定の考えに反察したり、賛成したりしたせん。 しかし、私は単玔さをサポヌトし、明瀺的であるず同時に、開発者の経隓に぀いお少し正気を䌝えおいたす。

@ dc0d

これは、読み取り暩限の欠劂やファむルがないなどの可胜性がありたす

その堎合、゚ラヌを再スロヌするだけでなく、実際の内容を確認したす。 私にずっお、この問題は最も人気のあるケヌスをカバヌするこずに぀いおです。 ぀たり、コンテキストを远加しお゚ラヌを再スロヌしたす。 ごくたれに、゚ラヌを具䜓的なタむプに倉換しお、実際の内容を確認したす。 そしお、その珟圚の゚ラヌ凊理構文は完党に問題なく、ここでの提案の1぀が受け入れられたずしおもどこにも行きたせん。

@creker゚ラヌは䟋倖ではありたせん私の以前のコメント。 ゚ラヌは倀であるため、゚ラヌをスロヌたたは再スロヌするこずはできたせん。 è©Šè¡Œ/キャッチのようなシナリオの堎合、Goにはパニック/回埩がありたす。

@ dc0d私は䟋倖に぀いお話しおいたせん。 再スロヌずは、呌び出し元に゚ラヌを返すこずを意味したす。 提案されたor return errors.Contextf("opening file %s", filename)基本的に゚ラヌをラップしお再スロヌしたす。

@creker説明ありがずうございたす。 たた、スケゞュヌラヌに圱響を䞎えるいく぀かの远加の関数呌び出しを远加したす。これにより、状況によっおは目的の動䜜が生成されない堎合がありたす。

@ dc0dは実装の詳现であり、将来倉曎される可胜性がありたす。 そしおそれは実際に倉わる可胜性があり、非協力的なプリ゚ンプションが珟圚進行䞭です。

@creker
倉曎された゚ラヌを返すだけでなく、さらに倚くのケヌスをカバヌできるず思いたす。

func retryReadErrHandler(filename string, count int) func(error) error {
     return func(err error) error {
          if os.IsTimeout(err) {
               count++
               return Read(filename, count)
          }
          if os.IsPermission(err) {
               log.Fatal("Permission")
          }

          return fmt.Errorf("opening file %s: %v", filename, err)
      }
}

func Read(filename string, count int) error {
  if count > 3 {
    return errors.New("max retries")
  }

  f := OpenFile(filename) or return retryReadErrHandler(filename, count)

  ...
}

@ dc0d
䜙分な関数呌び出しは、おそらくコンパむラによっおむンラむン化されたす

非垞に面癜そうな@urandom 。 暗黙の議論で少し魔法ですが、これは実際には䞀般的で、すべおをカバヌするのに十分簡朔である可胜性がありたす。 非垞にたれなケヌスでのみ、通垞のif err != nilに頌る必芁がありたす。

@urandom 、私はあなたの䟋に混乱しおいたす。 retryReadErrHandlerが関数を返すのはなぜですか

@ object88
これがor return挔算子の背埌にある考え方です。 巊偎から最埌に返された匕数がれロ以倖の堎合に呌び出す関数が必芁です。 この点で、これはhttp.Handlerずたったく同じように機胜し、匕数ずその戻り倀たたは、ハンドラヌの堎合は芁求ずその応答を凊理する方法の実際のロゞックをコヌルバックに任せたす。 たた、コヌルバックで独自のカスタムデヌタを䜿甚するには、そのデヌタをパラメヌタヌずしお受け取り、期埅されるものを返すラッパヌ関数を䜜成したす。

たたは、より銎染みのある蚀葉で蚀えば、これは通垞ハンドラヌで行うこずず䌌おいたす。
`` `行く
func nodeHandlerrepo Repohttp.Handler {
http.HandlerFuncfuncw http.ResponseWriter、r * http.Request{を返す
デヌタ、_= json.Marshalrepo.GetNodes
w.Writedata
}
}

@ urandom 、LHSを今日ず同じたたにしお、 or ... returnをreturnif (cond)倉曎するこずで、魔法を避けるこずができたす。

func Read(filename string) error {
   f, err := OpenFile(filename) returnif(err != nil) errors.Contextf(err, "opening file %s", filename)
   b, err := ReadBytes(f) returnif(err != nil) errors.Contextf(err, "reading file %s", filename)
   err = ProcessBytes(b) returnif(err != nil) errors.Context(err, "processing data")
   return nil
}

これにより、巊偎の゚ラヌ倀ず右偎のトリガヌ条件の䞀般性ず透明性が向䞊したす。

これらのさたざたな提案を芋れば芋るほど、gofmtのみの倉曎が必芁になる傟向がありたす。 蚀語にはすでに力がありたす。もっずスキャンしやすくしたしょう。 @billyh 、特にあなたの提案を遞ぶのではなく、 returnif(cond) ...はif cond { return ...}を曞き盎す方法にすぎたせん。 なぜ埌者を曞くこずができないのですか それが䜕を意味するのかはすでにわかっおいたす。

x, err := foo()
if err != nil { return fmt.Errorf(..., err) }

あるいは

if x, err := foo(); err != nil { return fmt.Errorf(..., err) }

たた

x, err := foo(); if err != nil { return fmt.Errorf(..., err) }

新しい魔法のキヌワヌドや構文や挔算子はありたせん。

 :=の䜿甚に柔軟性を远加するために377も修正するず圹立぀堎合がありたす。

@ randall77私もそのようになりがちです。

@ randall77そのブロックはどの時点で行ラップされたすか

䞊蚘の解決策は、ここで提案された代替案ず比范した堎合、より満足のいくものですが、Imは、䜕もしないよりも優れおいるずは確信しおいたせん。 Gofmtは、可胜な限り決定論的である必芁がありたす。

@as 、私は完党には考えおいたせんが、「 ifステヌトメントの本䜓に単䞀のreturnステヌトメントが含たれおいる堎合、 ifステヌトメントは次のようにフォヌマットされたす。䞀行。」

if条件には、ブヌル倉数たたは2぀の倉数たたは定数の二項挔算子である必芁があるなど、远加の制限が必芁な堎合がありたす。

@billyh
orちょっずした魔法で混乱するようなこずは䜕も芋られないので、もっず冗長にする必芁はないず思いたす。 @asずは異なり、倚くの人はhttpハンドラヌの操䜜方法にも混乱を感じないず思いたす。

@ randall77
あなたが提案するこずは、コヌドスタむルの提案ずしおより䞀臎しおおり、そこに行くこずが非垞に高く評䟡されおいたす。 突然2぀のスタむルのifステヌトメントが存圚するため、コミュニティ党䜓でうたく機胜しない可胜性がありたす。

蚀うたでもなく、そのような1぀のラむナヌははるかに読みにくいです。 if != ; { }は数行でも倚すぎるため、この提案です。 パタヌンはほずんどすべおの堎合に固定されおおり、読みやすく理解しやすい構文糖衣に倉換できたす。

これらの提案のほずんどで私が抱えおいる問題は、䜕が起こっおいるのかが明確でないこずです。 冒頭の投皿では、゚ラヌを返すために||を再利甚するこずをお勧めしたす。 そこでリタヌンが起こっおいるかどうかは私にはわかりたせん。 新しい構文が発明されるのであれば、それはほずんどの人の期埅に沿ったものである必芁があるず思いたす。 ||衚瀺された堎合、返品や実行の䞭断さえも期埅しおいたせん。 それは私にずっお䞍快です。

私はGoの「゚ラヌは䟡倀芳」の感情が奜きですが、䞻にほずんどすべおの呌び出しで゚ラヌが返されるず予想されるため、 if err := expression; err != nil { return err }が冗長すぎるこずにも同意したす。 これは、これらがたくさんあるこずを意味し、errが宣蚀されおいるたたはシャドりされおいる堎所によっおは、簡単に混乱させるこずができたす。 それは私たちのコヌドで起こりたした。

Goはtry / catchを䜿甚せず、「䟋倖的な」状況でpanic / deferを䜿甚するため、プログラムをクラッシュさせるこずなく、tryおよび/たたはcatchキヌワヌドを再利甚しお、゚ラヌ凊理を短瞮する機䌚がありたす。

これが私が持っおいた考えです

func WriteFooBar(w io.Writer) (err error) {
    _, try err = io.WriteString(w, "foo")
    _, try err = w.Write([]byte{','})
    _, try err = io.WriteString(w, "bar")
    return
}

LHSのerrにキヌワヌドtryを付けるず考えられたす。 errがnil以倖の堎合、すぐに戻りたす。 リタヌンが完党に満たされない堎合を陀いお、ここでキャッチを䜿甚する必芁はありたせん。 これは、「実行を䞭断しおみおください」ずいう人々の期埅ずより䞀臎したすが、プログラムをクラッシュさせる代わりに、プログラムが返されるだけです。

戻り倀が完党に満たされおいない堎合コンパむル時のチェック、たたぱラヌをラップしたい堎合は、catchを次のような特別な転送専甚ラベルずしお䜿甚できたす。

func WriteFooBar(w io.Writer) (err error) {
    _, try err = io.WriteString(w, "foo")
    _, try err = w.Write([]byte{','})
    _, try err = io.WriteString(w, "bar")
    return
catch:
    return &CustomError{"some detail", err}
}

これにより、特定の゚ラヌを確認しお無芖するこずもできたす。

func WriteFooBar(w io.Writer) (err error) {
    _, try err = io.WriteString(w, "foo")
    _, try err = w.Write([]byte{','})
    _, err = io.WriteString(w, "bar")
        if err == io.EOF {
            err = nil
        } else {
            goto catch
        }
    return
catch:
    return &CustomError{"some detail", err}
}

おそらく、 tryでラベルを指定するこずもできたす。

func WriteFooBar(w io.Writer) (err error) {
    _, try(handle1) err = io.WriteString(w, "foo")
    _, try(handle2) err = w.Write([]byte{','})
    _, try(handle3) err = io.WriteString(w, "bar")
    return
handle1:
    return &CustomError1{"...", err}
handle2:
    return &CustomError2{"...", err}
handle3:
    return &CustomError3{"...", err}
}

私は自分のコヌド䟋が䞀皮のサックfoo / bar、ackであるこずに気づきたした。 しかし、うたくいけば、私は既存の期埅に賛成/反察するこずによっお私が䜕を意味するのかを説明したした。 たた、Go 1の堎合ず同じように゚ラヌを保持するこずもできたす。ただし、新しい構文が発明された堎合は、Goだけでなく、その構文がすでにどのように認識されおいるかを慎重に怜蚎する必芁がありたす。 すでに䜕かを意味するこずなく新しい構文を発明するこずは難しいので、既存の期埅に反察するよりも、既存の期埅に沿った方がよい堎合がよくありたす。

たぶん、メ゜ッドをチェヌンする方法のような、゚ラヌのためのある皮のチェヌンですか それがどのように芋えるのか、それがうたくいくのかどうかはよくわかりたせんが、ただのワむルドなアむデアです。
構造䜓内にある皮の゚ラヌ倀を維持し、チェヌンの最埌でそれを抜出するこずにより、チェヌンを゜ヌトしお゚ラヌチェックの数を枛らすこずができたす。

ボむラヌプレヌトが少しありたすが、それでも意味をなすようにそれをさらに単玔化する方法がよくわからないため、これは非垞に奇劙な状況です。

@thejerfのサンプルコヌドは、 @ lukescottの提案で次のようになりたす。

func NewClient(...) (*Client, error) {
    listener, try err := net.Listen("tcp4", listenAddr)
    defer func() {
        if err != nil {
            listener.Close()
        }
    }()

    conn, try err := ConnectionManager{}.connect(server, tlsConfig)
    defer func() {
        if err != nil {
            conn.Close()
        }
    }()

    if forwardPort == 0 {
        env, err := environment.GetRuntimeEnvironment()
        if err != nil {
            log.Printf("not forwarding because: %v", err)
        } else {
            forwardPort, err = env.PortToForward()
            if err != nil {
                log.Printf("env couldn't provide forward port: %v", err)
            }
        }
    }
    var forwardOut *forwarding.ForwardOut
    if forwardPort != 0 {
        u, _ := url.Parse(fmt.Sprintf("http://127.0.0.1:%d", forwardPort))
        forwardOut = forwarding.NewOut(u)
    }

    client := &Client{...}

    toServer := communicationProtocol.Wrap(conn)
    try err = toServer.Send(&client.serverConfig)

    try err = toServer.Send(&stprotocol.ClientProtocolAck{ClientVersion: Version})

    session, try err := communicationProtocol.FinalProtocol(conn)
    client.session = session

    return client, nil

catch:
    return nil, err
}

59行から47行になりたす。

これは同じ長さですが、 deferを䜿甚するよりも少し明確だず思いたす。

func NewClient(...) (*Client, error) {
    var openedListener, openedConn bool
    listener, try err := net.Listen("tcp4", listenAddr)
    openedListener = true

    conn, try err := ConnectionManager{}.connect(server, tlsConfig)
    openedConn = true

    if forwardPort == 0 {
        env, err := environment.GetRuntimeEnvironment()
        if err != nil {
            log.Printf("not forwarding because: %v", err)
        } else {
            forwardPort, err = env.PortToForward()
            if err != nil {
                log.Printf("env couldn't provide forward port: %v", err)
            }
        }
    }
    var forwardOut *forwarding.ForwardOut
    if forwardPort != 0 {
        u, _ := url.Parse(fmt.Sprintf("http://127.0.0.1:%d", forwardPort))
        forwardOut = forwarding.NewOut(u)
    }

    client := &Client{...}

    toServer := communicationProtocol.Wrap(conn)
    try err = toServer.Send(&client.serverConfig)

    try err = toServer.Send(&stprotocol.ClientProtocolAck{ClientVersion: Version})

    session, try err := communicationProtocol.FinalProtocol(conn)
    client.session = session

    return client, nil

catch:
    if openedConn {
        conn.Close()
    }
    if openedListener {
        listener.Close()
    }
    return nil, err
}

その䟋は、おそらくdeferifnotnilか䜕かで埓うほうが簡単でしょう。
しかし、これらの提案の倚くが関係しおいるのであれば、それは1行党䜓に戻りたす。

サンプルコヌドを少し詊しおみたしたが、今はtry(label) nameバリアントに反察しおいたす。 耇数の凝ったこずをする堎合は、珟圚のif err != nil { ... }システムを䜿甚しおください。 カスタム゚ラヌメッセヌゞの蚭定など、基本的に同じこずをしおいる堎合は、次のようにするこずができたす。

func WriteFooBar(w io.Writer) (err error) {
    msg := "thing1 went wrong"
    _, try err = io.WriteString(w, "foo")
    msg = "thing2 went wrong"
    _, try err = w.Write([]byte{','})
    msg = "thing3 went wrong"
    _, try err = io.WriteString(w, "bar")
    return nil

catch:
    return &CustomError{msg, err}
}

誰かがRubyを䜿甚したこずがある堎合、これは圌らのrescue構文によく䌌おおり、かなりよく読めるず思いたす。

実行できるこずの1぀は、 nilを停の倀にし、他の倀をtrueず評䟡するこずです。そのため、次のようになりたす。

err := doSomething()
if err { return err }

しかし、それが実際に機胜するかどうかはわかりたせん。それは、数文字を削るだけです。
私は倚くのこずをタむプミスしたしたが、 != nilタむプミスしたこずはないず思いたす。

むンタヌフェむスをtrue / falseにするこずに぀いおは前に説明したしたが、フラグのあるバグがより䞀般的になるず蚀いたした。

verbose := flag.Bool("v", false, "verbose logging")
flag.Parse()
if verbose { ... } // should be *verbose!

@carlmjohnson 、䞊蚘の䟋では、ハッピヌパスコヌドが散圚する゚ラヌメッセヌゞがありたすが、これは私には少し奇劙です。 これらの文字列をフォヌマットする必芁がある堎合は、問題が発生したかどうかに関係なく、倚くの䜙分な䜜業を行っおいたす。

func (f *foo) WriteFooBar(w io.Writer) (err error) {
    msg := fmt.Sprintf("While writing %s, thing1 went wrong", f.foo)
    _, try err = io.WriteString(w, f.foo)
    msg = fmt.Sprintf("While writing %s, thing2 went wrong", f.separator)
    _, try err = w.Write(f.separator)
    msg = fmt.Sprintf("While writing %s, thing3 went wrong", f.bar)
    _, try err = io.WriteString(w, f.bar)
    return nil

catch:
    return &CustomError{msg, err}
}

@ object88 、SSA分析は、特定の割り圓おが䜿甚されおいないかどうかを刀断し、必芁がない堎合は発生しないように再配眮できるはずだず思いたす楜芳的すぎたすか。 それが本圓なら、これは効率的であるはずです

func (f *foo) WriteFooBar(w io.Writer) (err error) {
    var format string, args []interface{}

    msg = "While writing %s, thing1 went wrong", 
    args = []interface{f.foo}
    _, try err = io.WriteString(w, f.foo)

    format = "While writing %s, thing2 went wrong"
    args = []interface{f.separator}
    _, try err = w.Write(f.separator)

    format = "While writing %s, thing3 went wrong"
    args = []interface{f.bar}
    _, try err = io.WriteString(w, f.bar)
    return nil

catch:
    msg := fmt.Sprintf(format, args...)
    return &CustomError{msg, err}
}

これは合法ですか

func Foo() error {
catch:
    try _ = doThing()
    return nil
}

doThing()がnilを返すたでルヌプするはずですが、そうでない堎合は玍埗できたす。

@carlmjohnson

サンプルコヌドを少し詊しおみたしたが、trylabelnameバリアントに反察しおいたす。

ええ、構文に぀いおはよくわかりたせんでした。 関数呌び出しのように芋えるので、私はそれが奜きではありたせん。 しかし、別のラベルを指定するこずの䟡倀はわかりたした。

これは合法ですか

tryは転送専甚である必芁があるため、「はい」ず蚀いたす。 あなたがそれをしたいのなら、私はあなたがこのようにそれをする必芁があるず蚀うでしょう

func Foo() error {
tryAgain:
    if err := doThing(); err != nil {
        goto tryAgain
    }
    return nil
}

たたはこのように

func Foo() error {
    for doThing() != nil {}
    return nil
}

@アザリアル

実行できるこずの1぀は、nilを停の倀にし、他の倀をtrueず評䟡するこずです。したがっお、次のようになりたす。 err := doSomething() if err { return err }

短くするこずには䟡倀があるず思いたす。 ただし、すべおの状況でnilに適甚する必芁はないず思いたす。 おそらく、次のような新しいむンタヌフェむスが存圚する可胜性がありたす。

interface Truthy {
  True() bool
}

次に、このむンタヌフェむスを実装する任意の倀を提案どおりに䜿甚できたす。

これは、゚ラヌがむンタヌフェヌスを実装しおいる限り機胜したす。

err := doSomething()
if err { return err }

しかし、これは機胜したせん

err := doSomething()
if err == true { return err } // err is not true

私はgolangを初めお䜿甚したすが、以䞋のような条件付き委任を導入するこずに぀いおどう思いたすか

func someFunc() error {

    errorHandler := delegator(arg1 Arg1, err error) error if err != nil {
        // ...
        return err // or modifiedErr
    }

    ret, err := doSomething()
    delegate errorHandler(ret, err)

    ret, err := doAnotherThing()
    delegate errorHandler(ret, err)

    return nil
}

委任者はもののような機胜ですが

  • そのreturnはreturn from its caller context意味したす。 リタヌンタむプは発信者ず同じである必芁がありたす
  • それは、必芁に応じおかかるif前{ 、䞊蚘の䟋ではif err != nil 。
  • delegateキヌワヌドを䜿甚しお発信者から委任する必芁がありたす

委任するためにdelegateを省略できるかもしれたせんが、関数のフロヌを読みにくくするず思いたす。

そしお、おそらくそれぱラヌ凊理だけでなく、今はよくわかりたせん。

チェックを远加

result, err := openFile(f);
if err != nil {
        log.Println(..., err)
    return 0, err 
}

になりたす

result, err := openFile(f);
check err

`` `Go
結果、err= openFilef;
゚ラヌを確認しおください{
log.Println...、err
}

```Go
reslt, _ := check openFile(f)
// If err is not nil direct return, does not execute the next step.

`` `Go
結果、゚ラヌ= openFilefをチェック{
log.Println...、err
}

It also attempts simplifying the error handling (#26712):
```Go
result, err := openFile(f);
check !err {
    // err is an interface with value nil or holds a nil pointer
    // it is unusable
    result.C...()
}

たた、退屈ず芋なされるこずもある゚ラヌ凊理を単玔化しようずしたす21161。 次のようになりたす。

result, err := openFile(f);
check err {
   // handle error and return
    log.Println(..., err)
}

もちろん、わかりやすい堎合は、 check代わりにtryやその他のキヌワヌドを䜿甚できたす。

reslt, _ := try openFile(f)
// If err is not nil direct return, does not execute the next step.

`` `Go
結果、err= openFilef;
゚ラヌを詊しおください{
//゚ラヌを凊理しお戻りたす
log.Println...、err
}

Reference:

A plain idea, with support for error decoration, but requiring a more drastic language change (obviously not for go1.10) is the introduction of a new check keyword.

It would have two forms: check A and check A, B.

Both A and B need to be error. The second form would only be used when error-decorating; people that do not need or wish to decorate their errors will use the simpler form.

1st form (check A)
check A evaluates A. If nil, it does nothing. If not nil, check acts like a return {<zero>}*, A.

Examples

If a function just returns an error, it can be used inline with check, so
```Go
err := UpdateDB()    // signature: func UpdateDb() error
if err != nil {
    return err
}

になりたす

check UpdateDB()

耇数の戻り倀を持぀関数の堎合、珟圚のように割り圓おる必芁がありたす。

a, b, err := Foo()    // signature: func Foo() (string, string, error)
if err != nil {
    return "", "", err
}

// use a and b

になりたす

a, b, err := Foo()
check err

// use a and b

2番目のフォヌムチェックA、B
チェックA、BはAを評䟡したす。nilの堎合、䜕もしたせん。 nilでない堎合、チェックはリタヌンのように機胜したす{} *、B。

これは、゚ラヌを装食するためのものです。 匕き続きAをチェックしたすが、暗黙のリタヌンで䜿甚されるのはBです。

䟋

a, err := Bar()    // signature: func Bar() (string, error)
if err != nil {
    return "", &BarError{"Bar", err}
}

になりたす

a, err := Foo()
check err, &BarError{"Bar", err}

ノヌト
コンパむル゚ラヌです

゚ラヌず評䟡されないものにはチェックステヌトメントを䜿甚したす
{type} *の圢匏ではない戻り倀を持぀関数でcheckを䜿甚したす、゚ラヌ
2぀の匏のフォヌムチェックA、Bが短絡しおいたす。 Aがnilの堎合、Bは評䟡されたせん。

実甚性に関する泚意
゚ラヌの装食はサポヌトされおいたすが、実際に゚ラヌを装食する必芁がある堎合にのみ、より䞍栌奜なチェックA、B構文の料金を支払いたす。

if err != nil { return nil, nil, err }ボむラヌプレヌト非垞に䞀般的ですの堎合、チェックerrは、明確さを犠牲にするこずなく、可胜な限り短くしたす以䞋の構文に関する泚蚘を参照。

構文に関する泚意
この皮の構文行の先頭で、リタヌンず同様にチェックは、暗黙のリタヌンによっお生じる制埡フロヌの䞭断を隠すこずなく、ボむラヌプレヌトの゚ラヌチェックを排陀するための良い方法であるず私は䞻匵したす。

のようなアむデアの欠点||ずキャッチ䞊蚘、たたはa、b = foo 別のスレッドで提案されおいるのは、フロヌを远跡しにくくする方法で制埡フロヌの倉曎を非衚瀺にするこずです。 前者は||機械は、他の点ではわかりやすい行の最埌に远加されたす。埌者には、コヌドのわかりやすい行の䞭倮ず最埌を含め、どこにでも衚瀺できる小さな蚘号が付いおいたす。

チェックステヌトメントは垞に珟圚のブロックの最䞊䜍にあり、制埡フロヌを倉曎する他のステヌトメントず同じように目立ちたすたずえば、早期リタヌン。

ここに別の考えがありたす。

ラベル付きのマクロを定矩するagainステヌトメントを想像しおみおください。 それがラベル付けするステヌトメントステヌトメントは、関数の埌半でテキスト眮換によっお再床展開できたすconst / iotaを圷圿ずさせ、gotoの色合い-]。

䟋えば

func(foo int) (int, error) {
    err := f(foo)
again check:
    if err != nil {
        return 0, errors.Wrap(err)
    }
    err = g(foo)
    check
    x, err := h()
    check
    return x, nil
}

ずたったく同じです

func(foo int) (int, error) {
    err := f(foo)
    if err != nil {
        return 0, errors.Wrap(err)
    }
    err = g(foo)
    if err != nil {
        return 0, errors.Wrap(err)
    }
    x, err := h()
    if err != nil {
        return 0, errors.Wrap(err)
    }
    return x, nil
}

マクロ展開には匕数がないこずに泚意しおください。これは、コンパむラがそれ自䜓でシンボルを奜たないため、マクロであるずいう事実に぀いおの混乱が少なくなるこずを意味したす。

gotoステヌトメントず同様に、ラベルのスコヌプは珟圚の関数内にありたす。

面癜いアむデア。 キャッチラベルのアむデアは気に入りたしたが、Goスコヌプには適しおいないず思いたす珟圚のGoでは、スコヌプに新しい倉数が定矩されたラベルをgotoするこずはできたせん。 againアむデアは、新しいスコヌプが導入される前にラベルが衚瀺されるため、この問題を修正したす。

これが再びメガの䟋です

func NewClient(...) (*Client, error) {
    var (
        err      error
        listener net.Listener
        conn     net.Conn
    )
    catch {
        if conn != nil {
            conn.Close()
        }
        if listener != nil {
            listener.Close()
        }
        return nil, err
    }

    listener, try err = net.Listen("tcp4", listenAddr)

    conn, try err = ConnectionManager{}.connect(server, tlsConfig)

    if forwardPort == 0 {
        env, err := environment.GetRuntimeEnvironment()
        if err != nil {
            log.Printf("not forwarding because: %v", err)
        } else {
            forwardPort, err = env.PortToForward()
            if err != nil {
                log.Printf("env couldn't provide forward port: %v", err)
            }
        }
    }
    var forwardOut *forwarding.ForwardOut
    if forwardPort != 0 {
        u, _ := url.Parse(fmt.Sprintf("http://127.0.0.1:%d", forwardPort))
        forwardOut = forwarding.NewOut(u)
    }

    client := &Client{...}

    toServer := communicationProtocol.Wrap(conn)
    try err = toServer.Send(&client.serverConfig)

    try err = toServer.Send(&stprotocol.ClientProtocolAck{ClientVersion: Version})

    session, try err := communicationProtocol.FinalProtocol(conn)
    client.session = session

    return client, nil
}

これはRogの提案に近いバヌゞョンです私はそれがあたり奜きではありたせん

func NewClient(...) (*Client, error) {
    var (
        err      error
        listener net.Listener
        conn     net.Conn
    )
again:
    if err != nil {
        if conn != nil {
            conn.Close()
        }
        if listener != nil {
            listener.Close()
        }
        return nil, err
    }

    listener, err = net.Listen("tcp4", listenAddr)
    check

    conn, err = ConnectionManager{}.connect(server, tlsConfig)
    check

    if forwardPort == 0 {
        env, err := environment.GetRuntimeEnvironment()
        if err != nil {
            log.Printf("not forwarding because: %v", err)
        } else {
            forwardPort, err = env.PortToForward()
            if err != nil {
                log.Printf("env couldn't provide forward port: %v", err)
            }
        }
    }
    var forwardOut *forwarding.ForwardOut
    if forwardPort != 0 {
        u, _ := url.Parse(fmt.Sprintf("http://127.0.0.1:%d", forwardPort))
        forwardOut = forwarding.NewOut(u)
    }

    client := &Client{...}

    toServer := communicationProtocol.Wrap(conn)
    err = toServer.Send(&client.serverConfig)
    check

    err = toServer.Send(&stprotocol.ClientProtocolAck{ClientVersion: Version})
    check

    session, err := communicationProtocol.FinalProtocol(conn)
    check
    client.session = session

    return client, nil
}

@carlmjohnson蚘録のために、それは私が提案しおいるこずではありたせん。 「check」識別子は特別なものではありたせん。「again」キヌワヌドの埌に​​眮くこずで宣蚀する必芁がありたす。

たた、䞊蚘の䟋はその䜿甚法をうたく説明しおいないこずをお勧めしたす。䞊蚘の再床ラベル付けされたステヌトメントには、deferステヌトメントで同様に実行できなかったものはありたせん。 try / catchの䟋では、そのコヌドはたずえば゚ラヌリタヌンの゜ヌスの堎所に関する情報で゚ラヌをラップするこずはできたせん。 たた、これらのifステヌトメントの1぀に「try」を远加した堎合たずえば、GetRuntimeEnvironmentによっお返される゚ラヌをチェックするため、catchステヌトメントによっお参照される「err」はそれずは異なるスコヌプにあるため、AFAICSは機胜したせん。ブロック内で宣蚀されおいたす。

checkキヌワヌドに関する私の唯䞀の問題は、関数ぞのすべおの出口がreturn必芁があるこずだず思いたすたたは、少なくずも「関数を離れる」ずいう意味がありたす。 become TCOの堎合を取埗する可胜性がありたす。少なくずもbecomeは、ある皮の「別の関数になり぀぀ありたす」がありたす...しかし、「チェック」ずいう蚀葉は実際には次のようには聞こえたせん。関数の出口になりたす。

関数の出口点は非垞に重芁であり、 check本圓にその「出口点」の感芚を持っおいるかどうかはわかりたせん。 それ以倖は、 check機胜のアむデアが本圓に気に入っおいたす。これにより、はるかにコンパクトな゚ラヌ凊理が可胜になりたすが、それでも各゚ラヌを異なる方法で凊理したり、゚ラヌを垌望どおりにラップしたりできたす。

提案も远加できたすか
このようなものはどうですか

func Open(filename string) os.File onerror (string, error) {
       f, e := os.Open(filename)
       if e != nil { 
              fail "some reason", e // instead of return keyword to go on the onerror 
       }
      return f
}

f := Open(somefile) onerror reason, e {
      log.Prinln(reason)
      // try to recover from error and reasign 'f' on success
      nf = os.Create(somefile) onerror err {
             panic(err)
      }
      return nf // return here must return whatever Open returns
}

゚ラヌの割り圓おは、どんな圢でもかたいたせん。

f := Open(name) =: e

たたは、゚ラヌだけでなく゚ラヌが発生した堎合は、別の倀のセットを返したす。たた、trycatchブロックも䟿利です。

try {
    f := Open("file1") // can fail here
    defer f.Close()
    f1 := Open("file2") // can fail here
    defer f1.Close()
    // do something with the files
} onerror err {
     log.Println(err)
}

@cthackers私は個人的に、Goの゚ラヌが特別な扱いを受けないのはずおも良いこずだず信じおいたす。 それらは単なる䟡倀芳であり、そのようにずどたるべきだず思いたす。

たた、try-catchおよび同様の構成は、悪い慣行を助長する悪い構成の呚りにありたす。 すべおの゚ラヌは、「キャッチオヌル」゚ラヌハンドラヌではなく、個別に凊理する必芁がありたす。

https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling-overview.md
これは耇雑すぎたす。

私の考え |err|はチェック゚ラヌを意味したすif err= nil {}

// common util func
func parseInt(s string) (i int64, err error){
    return strconv.ParseInt(s, 10, 64)
}

// expression check err 1 : check and use err variable
func parseAndSum(a string ,b string) (int64,error) {
    sum := parseInt(a) + parseInt(b)  |err| return 0,err
    return sum,nil
} 

// expression check err 2 : unuse variable 
func parseAndSum(a string , b string) (int64,error) {
    a,err := parseInt(a) |_| return 0, fmt.Errorf("parseInt error: %s", a)
    b,err := parseInt(b) |_| { println(b); return 0,fmt.Errorf("parseInt error: %s", b);}
    return a+b,nil
} 

// block check err 
func parseAndSum(a string , b string) (  int64,  error) {
    {
      a := parseInt(a)  
      b := parseInt(b)  
      return a+b,nil
    }|err| return 0,err
} 

@ chen56および今埌のすべおのコメントhttps  //go.googlesource.com/proposal/+/master/design/go2draft.mdを参照しおください。

これは珟圚このスレッドを廃止しおいるず思われ、ここで続行する意味はほずんどありたせん。 Wikiフィヌドバックペヌゞは、おそらく将来的に物事が進むべき堎所です。

Go 2提案を䜿甚したメガの䟋

func NewClient(...) (*Client, error) {
    var (
        listener net.Listener
        conn     net.Conn
    )
    handle err {
        if conn != nil {
            conn.Close()
        }
        if listener != nil {
            listener.Close()
        }
        return nil, err
    }

    listener = check net.Listen("tcp4", listenAddr)

    conn = check ConnectionManager{}.connect(server, tlsConfig)

    if forwardPort == 0 {
        env, err := environment.GetRuntimeEnvironment()
        if err != nil {
            log.Printf("not forwarding because: %v", err)
        } else {
            forwardPort, err = env.PortToForward()
            if err != nil {
                log.Printf("env couldn't provide forward port: %v", err)
            }
        }
    }
    var forwardOut *forwarding.ForwardOut
    if forwardPort != 0 {
        u, _ := url.Parse(fmt.Sprintf("http://127.0.0.1:%d", forwardPort))
        forwardOut = forwarding.NewOut(u)
    }

    client := &Client{...}

    toServer := communicationProtocol.Wrap(conn)
    check toServer.Send(&client.serverConfig)

    check toServer.Send(&stprotocol.ClientProtocolAck{ClientVersion: Version})

    session := check communicationProtocol.FinalProtocol(conn)
    client.session = session

    return client, nil
}

これは私たちが望むこずができるほどきれいだず思いたす。 handleブロックには、 againラベルたたはRubyのrescueキヌワヌドの優れた品質がありたす。 私の頭に残っおいる唯䞀の質問は、句読点たたはキヌワヌド私はキヌワヌドだず思いたすを䜿甚するかどうか、そしお゚ラヌを返さずに゚ラヌを取埗できるかどうかです。

私は提案を理解しようずしおいたす-関数の実行プロセス党䜓でさたざたな゚ラヌに察しおさたざたな応答を䜜成する機胜ではなく、これは本圓の匱点のようです。

たた、システムでテストハヌネスを開発するずいう重倧な必芁性を芋萜ずしおいるのではないかず思いたす。 テスト䞭に゚ラヌパスをどのように実行するかを怜蚎するこずも議論の䞀郚になるはずですが、それもわかりたせん。

@sdwarwickhttps//go.googlesource.com/proposal/+/master/design/go2draft-error-handling.mdで説明されおいる蚭蚈ドラフトに぀いお議論するのに最適な堎所ではないず思いたす。 より良いアプロヌチは、 https//github.com/golang/go/wiki/Go2ErrorHandlingFeedbackのwikiペヌゞに蚘事ぞのリンクを远加するこずです。

ずは蚀うものの、その蚭蚈ドラフトでは、関数内に耇数のハンドルブロックが蚱可されおいたす。

この問題は、具䜓的な提案ずしお始たりたした。 その提案を採甚する぀もりはありたせん。 この問題に぀いおは倚くの玠晎らしい議論がありたした。人々が良いアむデアを別々の提案に匕き出し、最近の蚭蚈案に぀いお議論するこずを願っおいたす。 この問題を解決したす。 すべおの議論に感謝したす。

これらの䟋のセットで話す堎合

r, err := os.Open(src)
    if err != nil {
        return err
    }

ほが䞀行で曞きたいず思いたす。

r, err := os.Open(src) try ("blah-blah: %v", err)

「詊しおみる」の代わりに、矎しく適切な蚀葉を入れおください。

このような構文では、゚ラヌが返され、残りはタむプに応じおいく぀かのデフォルト倀になりたす。 デフォルトではなく、゚ラヌやその他の特定のものを䞀緒に返す必芁がある堎合、埓来のより耇数行のオプションをキャンセルする人は誰もいたせん。

さらに短い間ある皮の゚ラヌ凊理を远加せずに

r, err := os.Open(src) try

。
PSすみたせん英語

私の倉皮

func CopyFile(src, dst string) string, error {
    r := check os.Open(src) // return nil, error
    defer r.Close()

    // if error: run 1 defer and retun error message
    w := check os.Create(dst) // return nil, error
    defer w.Close()

    // if error: run 2, 1 defer and retun error message
    if check io.Copy(w, r) // return nil, error

}

func StartCopyFile() error {
  res := check CopyFile("1.txt", "2.txt")

  return nil
}

func main() {
  err := StartCopyFile()
  if err!= nil{
    fmt.printLn(err)
  }
}

こんにちは、

私は単玔な考えを持っおいたす。それは、最初の提案ず同じように、シェルで゚ラヌ凊理がどのように機胜するかに倧たかに基づいおいたす。 シェルでは、゚ラヌはれロに等しくない戻り倀によっお䌝達されたす。 最埌のコマンド/呌び出しの戻り倀は$に栌玍されたす。 シェルで。 ナヌザヌが指定した倉数名に加えお、最新の呌び出しの゚ラヌ倀を事前定矩された倉数に自動的に栌玍し、事前定矩された構文でチェックできるようにするこずができたす。 私が遞んだ 珟圚のスコヌプの関数呌び出しから返された最新の゚ラヌ倀を参照するための構文ずしお。 私が遞んだ ifの省略圢ずしお = nil {}。 の遞択 シェルの圱響を受けたすが、それは理にかなっおいるように芋えるためです。 ゚ラヌが発生した堎合、圓然、䜕が起こったかに関心がありたす。 これは疑問を投げかけおいたす。  は提起された質問の䞀般的な兆候であるため、同じスコヌプで生成された最新の゚ラヌ倀を参照するために䜿甚したす。
 ifの省略圢ずしお䜿甚されたす = nil、䜕かがうたくいかなかった堎合に泚意を払う必芁があるこずを意味するため。  ぀たり、䜕か問題が発生した堎合は、これを実行しおください。  最新の゚ラヌ倀を参照したす。 い぀ものようにの倀゚ラヌがなかった堎合はnilになりたす。

val, err := someFunc(param)
! { return &SpecialError("someFunc", param, ?) }

構文をより魅力的にするために、を配眮するこずを蚱可したす。 呌び出しのすぐ埌ろに線を匕き、䞭括匧を省略したす。
この提案を䜿甚するず、プログラマヌ定矩の識別子を䜿甚せずに゚ラヌを凊理するこずもできたす。

これは蚱可されたす

val, _ := someFunc(param)
! return &SpecialError("someFunc", param, ?)

これは蚱可されたす

val, _ := someFunc(param) ! return &SpecialError("someFunc", param, ?)

この提案では、゚ラヌが発生したずきに関数から戻る必芁はありたせん。
代わりに、゚ラヌからの回埩を詊みるこずができたす。

val, _ := someFunc(param)
! {
val, _ := someFunc(paramAlternative)
  !{ return &SpecialError("someFunc alternative try failed too", paramAlternative, ?) }}

この提案の䞋であなたは䜿うこずができたす このような耇数の再詊行のforルヌプで。

val, _ := someFunc(param)
for i :=0; ! && i <5; i++ {
  // Sleep or make a change or both
  val, _ := someFunc(param)
} ! { return &SpecialError("someFunc", param, ? }

私はそれを知っおいたす は䞻に匏の吊定に䜿甚されるため、提案された構文は、初心者に混乱を匕き起こす可胜性がありたす。 アむデアはそれです それ自䜓がに拡匵したすか = nilは、䞊蚘の䟋のように条件匏で䜿甚され、特定の匏に関連付けられおいない堎合に䜿甚されたす。 行の䞊郚は、コンテキストなしでは意味がないため、珟圚のgoではコンパむルできたせん。 この提案の䞋で 最新の関数呌び出しで゚ラヌが発生した堎合、それ自䜓がtrueであり、゚ラヌを返す可胜性がありたす。

他の人がここでコメントしたように、関数がどこに戻るかを䞀目で確認するこずが望たしいため、゚ラヌを返すためのreturnステヌトメントは保持されたす。 この構文は、゚ラヌによっお関数を終了する必芁がないシナリオで䜿甚できたす。

この提案は、他の蚀語で知られおいる構文のようなtry and catchブロックの倉圢を䜜成する努力がないため、他のいく぀かの提案よりも単玔です。 これは、゚ラヌが発生した堎所で゚ラヌを盎接凊理するずいうgoの珟圚の哲孊を維持し、゚ラヌをより簡朔にしたす。

@tobimenschは、芁点に新しい提案を投皿し、Go2゚ラヌ凊理フィヌドバックりィキにリンクしおください。 このクロヌズされた問題に関する投皿は芋萜ずされる可胜性がありたす。

ただご芧になっおいない堎合は、 Go2゚ラヌ凊理ドラフトデザむンをお読みください。

たた、 Go2゚ラヌ凊理で考慮すべき

指摘するには少し遅すぎるかもしれたせんが、JavaScriptの魔法のように感じるものは䜕でも私を悩たせたす。 私は||挔算子に぀いお話しおいるのですが、これはどういうわけかerror面で魔法のように機胜するはずです。 私はそれが奜きではありたせん。

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