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
첫 번째 반환 된 변수에 직접 액세스 할 수있는 방법이 없습니까?
답변
다중 값 반환 함수의 경우 함수를 호출 할 때 결과의 특정 값에 대한 필드 또는 메서드를 참조 할 수 없습니다.
그들 중 하나가 인 경우 error
, 그것은 거기의 이유 (기능이 있습니다 실패) 당신은해야 하지 당신이 할 경우 바이 패스, 이후의 코드가 있기 때문에 수도 있습니다 (예 : 런타임 공황의 결과)도 비참하게 실패합니다.
그러나 어떤 상황에서도 코드가 실패하지 않을 것이라는 것을 알고 있는 상황이있을 수 있습니다 . 이러한 경우에는 삭제 (또는 여전히 발생하는 경우 런타임 패닉 발생) 하는 도우미 함수 (또는 메서드)를 제공 할 수 있습니다 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
특정 입력 값에 대해, 당신은 헬퍼 만들 수 있습니다 Must()
을 반환하지 않을 기능을 error
하지만 여전히 발생하면 런타임 공황 인상을 :
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
.
답변
네, 있습니다.
놀랍죠? 간단한 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-
슬라이스 / 배열에서와 마찬가지로 값 번호를 선택한 다음 실제 값을 얻기위한 유형을 선택하는 방법에 주목하십시오.
이 기사 에서 그 뒤에 숨겨진 과학에 대해 더 많이 읽을 수 있습니다 . 저자에 대한 크레딧.
답변
아니요, 첫 번째 값에 직접 액세스 할 수 없습니다.
나는 이것에 대한 해킹이 “item”과 “err”대신에 값의 배열을 반환하는 것이라고 생각한다. 그리고 나서 그냥 그렇게
item, _ := Get(1)[0]
하지만 나는 이것을 추천하지 않을 것이다.
답변
이쪽은 어때?
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]
}
}