Goでのエラー処理のため、私はしばしば複数の値の関数になります。これまでのところ、これを管理する方法は非常に面倒であり、よりクリーンなコードを作成するためのベストプラクティスを探しています。
私には次の機能があるとしましょう:
type Item struct {
Value int
Name string
}
func Get(value int) (Item, error) {
// some code
return item, nil
}
item.Value
に新しい変数をエレガントに割り当てるにはどうすればよいですか。エラー処理を導入する前に、私の関数はitem
を返しました。
val := Get(1).Value
今、私はこれを行います:
item, _ := Get(1)
val := item.Value
最初に返された変数に直接アクセスする方法はありませんか?
複数値を返す関数の場合、関数を呼び出すときに結果の特定の値のフィールドまたはメソッドを参照できません。
そして、そのうちの1つがerror
である場合、reason(これは関数mightが失敗する)であり、 notをバイパスすると、後続のコードmightも悲惨に失敗します(たとえば、実行時のパニックになります)。
ただし、どのような状況でもコードが失敗しないknowの状況があるかもしれません。これらの場合、helper関数(またはメソッド)を提供して、error
を破棄します(または、まだ発生している場合はランタイムパニックを発生させます)。
これは、コードから関数の入力値を提供し、それらが機能することがわかっている場合です。
これのすばらしい例は template
および regexp
パッケージです:コンパイル時に有効なテンプレートまたは正規表現を提供すれば、いつでもそうであると確信できます実行時にエラーなしで解析されました。このため、template
パッケージは Must(t *Template, err error) *Template
関数を提供し、regexp
パッケージは MustCompile(str string) *Regexp
関数を提供します。入力が保証される場所であるため、error
sを返しません。有効であること。
例:
// "text" is a valid template, parsing it will not fail
var t = template.Must(template.New("name").Parse("text"))
// `^[a-z]+\[[0-9]+\]$` is a valid regexp, always compiles
var validID = regexp.MustCompile(`^[a-z]+\[[0-9]+\]$`)
特定のGet()
が特定の入力値に対してerror
を生成しないことが確実な場合、error
を返さずに実行時にパニックを発生させるヘルパーMust()
関数を作成できます。
func Must(i Item, err error) Item {
if err != nil {
panic(err)
}
return i
}
ただし、成功することが確実な場合にのみ、すべての場合にこれを使用するべきではありません。使用法:
val := Must(Get(1)).Value
代替/簡略化
Get()
呼び出しをヘルパー関数に組み込むと、さらに単純化できます。それをMustGet
と呼びましょう。
func MustGet(value int) Item {
i, err := Get(value)
if err != nil {
panic(err)
}
return i
}
使用法:
val := MustGet(1).Value
いくつかの興味深い/関連する質問を参照してください:
いいえ。ただし、常にエラーを処理する必要があるため、これは良いことです。
エラー処理を延期するために使用できるテクニックがあります。 エラーは値です Rob Pikeを参照してください。
ew := &errWriter{w: fd} ew.write(p0[a:b]) ew.write(p1[c:d]) ew.write(p2[e:f]) // and so on if ew.err != nil { return ew.err }
このブログ投稿の例では、errWriter
の呼び出しが完了するまでエラー処理を延期するwrite
型を作成する方法を示しています。
いいえ、最初の値に直接アクセスすることはできません。
このためのハックは、「item」と「err」の代わりに値の配列を返し、それから単にitem, _ := Get(1)[0]
を行うことですが、これはお勧めしません。
はいあります。
驚いたね単純なmute
関数を使用して、複数の戻り値から特定の値を取得できます。
package main
import "fmt"
import "strings"
func µ(a ...interface{}) []interface{} {
return a
}
type A struct {
B string
C func()(string)
}
func main() {
a := A {
B:strings.TrimSpace(µ(E())[1].(string)),
C:µ(G())[0].(func()(string)),
}
fmt.Printf ("%s says %s\n", a.B, a.C())
}
func E() (bool, string) {
return false, "F"
}
func G() (func()(string), bool) {
return func() string { return "Hello" }, true
}
https://play.golang.org/p/IwqmoKwVm-
実際の値を取得するために、スライス/配列からタイプと同じように値番号を選択し、次にタイプを選択する方法に注意してください。
この記事 から、その背後にある科学の詳細を読むことができます。著者へのクレジット。
この方法はどうですか?
package main
import (
"fmt"
"errors"
)
type Item struct {
Value int
Name string
}
var items []Item = []Item{{Value:0, Name:"zero"},
{Value:1, Name:"one"},
{Value:2, Name:"two"}}
func main() {
var err error
v := Get(3, &err).Value
if err != nil {
fmt.Println(err)
return
}
fmt.Println(v)
}
func Get(value int, err *error) Item {
if value > (len(items) - 1) {
*err = errors.New("error")
return Item{}
} else {
return items[value]
}
}