단일 값 컨텍스트의 여러 값


110

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

첫 번째 반환 된 변수에 직접 액세스 할 수있는 방법이 없습니까?


3
item일반적으로 nil오류가 발생합니다. 먼저 오류를 확인하지 않으면이 경우 코드가 충돌합니다.
Thomas

답변:


83

다중 값 반환 함수의 경우 함수를 호출 할 때 결과의 특정 값에 대한 필드 또는 메서드를 참조 할 수 없습니다.

그들 중 하나가 인 경우 error, 그것은 거기의 이유 (기능이 있습니다 실패) 당신은해야 하지 당신이 할 경우 바이 패스, 이후의 코드가 있기 때문에 수도 있습니다 (예 : 런타임 공황의 결과)도 비참하게 실패합니다.

그러나 어떤 상황에서도 코드가 실패하지 않을 것이라는 것을 알고 있는 상황이있을 수 있습니다 . 이러한 경우에는 삭제 (또는 여전히 발생하는 경우 런타임 패닉 발생) 하는 도우미 함수 (또는 메서드)를 제공 할 수 있습니다 error.
코드에서 함수에 대한 입력 값을 제공하고 해당 값이 작동한다는 것을 알고있는 경우에 해당됩니다.
이에 대한 좋은 예는 templateregexp패키지입니다. 컴파일 타임에 유효한 템플릿 또는 정규 표현식을 제공하면 런타임시 오류없이 항상 구문 분석 할 수 있습니다. 이러한 이유로 template패키지는 Must(t *Template, err error) *Template기능을 regexp제공하고 패키지는 MustCompile(str string) *Regexp기능을 제공합니다 .errors는 의도 된 용도가 입력의 유효성이 보장되는 곳이기 때문입니다.

예 :

// "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

흥미로운 / 관련 질문을 참조하십시오.

golang에서 여러 반환을 구문 분석하는 방법

정상 기능에서 Golang의 'ok'와 같은 맵 반환


7

아니요,하지만 항상 오류를 처리해야하기 때문에 좋은 것입니다.

오류 처리를 연기하기 위해 사용할 수있는 기술이 있습니다. 오류는 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.


6

네, 있습니다.

놀랍죠? 간단한 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-

슬라이스 / 배열에서와 마찬가지로 값 번호를 선택한 다음 실제 값을 얻기위한 유형을 선택하는 방법에 주목하십시오.

이 기사 에서 그 뒤에 숨겨진 과학에 대해 더 많이 읽을 수 있습니다 . 저자에 대한 크레딧.


5

아니요, 첫 번째 값에 직접 액세스 할 수 없습니다.

나는 이것에 대한 해킹이 "item"과 "err"대신에 값의 배열을 반환하는 것이라고 생각한다. 그리고 나서 그냥 그렇게 item, _ := Get(1)[0] 하지만 나는 이것을 추천하지 않을 것이다.


3

이쪽은 어때?

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]
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.