Menu

Golang 다중 반환 값: (value, error)와 이름 있는 결과

Go 함수는 값을 여러 개 반환할 수 있습니다. 문법, (value, error) 관례, comma-ok 관용구, 이름 있는 결과, naked return, 빈 식별자를 다룹니다.

이 페이지에는 실행 가능한 에디터가 있습니다 - 편집하고 실행하면 결과를 바로 볼 수 있습니다.

값을 둘 이상 반환하기

결과 타입을 괄호 안에 나열합니다. 값은 쉼표로 구분해 반환하고, 받을 때도 같은 방식으로 받습니다.

내장 함수 minmax는 Go 1.21부터 있습니다. 호출하는 쪽은 모든 결과를 받아야 합니다. x := minMax(nums)assignment mismatch: 1 variable but minMax returns 2 values로 컴파일에 실패합니다.

(value, error) 관례

값을 두 개 반환하는 가장 흔한 이유는 실패를 알리기 위해서입니다. 관례상 오류는 마지막에 오고, 오류가 nil이 아니면 나머지 결과는 의미 없는 값으로 취급해야 합니다.

출력:

port: 8080
error: port "http": strconv.Atoi: parsing "http": invalid syntax
error: port out of range

실패하면 나머지 결과로 모두 제로 값(0, "", nil)을 반환하세요. 감싸기와 확인을 포함한 전체 패턴은 오류 처리 페이지에 있습니다.

comma-ok 관용구

일부 내장 연산은 첫 번째 값이 진짜인지 알려 주는 두 번째 bool을 선택적으로 반환합니다. 이 변수는 관례상 ok라고 부릅니다.

이 세 가지 형태(맵 조회, 타입 단언, 채널 수신)는 특별합니다. 대입하는 변수 개수에 따라 값을 하나 또는 둘 반환합니다. 직접 만든 함수는 그렇게 할 수 없습니다. 결과가 둘로 선언된 함수는 항상 둘을 반환합니다.

빈 식별자

_는 값을 받아서 버립니다. 필요 없는 결과에 쓰세요:

_, err := fmt.Sscan(input, &n)
key, _ := parseLine(line)

_로 오류를 무시해도 컴파일은 되므로, 호출이 실패할 수 없거나 실패해도 상관없다는 것을 알 때만 그렇게 하세요. 예를 들어 strings.Builder.WriteString은 항상 nil 오류를 반환하지만, 쓰기를 마친 파일의 close는 그렇지 않습니다.

이름 있는 결과

결과 매개변수에 이름을 붙일 수 있습니다. 함수 시작 부분에서 선언되어 제로 값으로 초기화되고, 값 없는 return은 그 변수들이 담고 있는 값을 반환합니다.

이름은 go doc 출력에 나타나므로 두 결과의 타입이 같을 때 도움이 됩니다. (quotient, remainder int)(int, int)보다 많은 것을 말해 줍니다.

긴 함수의 값 없는 return은 읽기 어렵습니다. 결과에 무엇이 담겼는지 보려면 위로 거슬러 올라가 훑어봐야 하기 때문입니다. 보통의 조언은 이렇습니다. 이름이 무언가를 설명해 줄 때 결과에 이름을 붙이고, 함수가 몇 줄짜리가 아니라면 return quotient, remainder처럼 명시적으로 쓰세요.

이름 있는 결과와 defer

지연된 함수는 return 문이 결과를 설정한 뒤, 그리고 호출자가 결과를 받기 전에 실행됩니다. 결과에 이름이 있으면 지연된 함수가 그 값을 읽고 바꿀 수 있습니다. 함수가 반환하는 모든 오류에 맥락을 덧붙이거나 패닉을 오류로 바꿀 때 이 방법을 씁니다.

이 코드는 load : empty name을 출력한 다음 <nil>을 출력합니다. return errors.New(...)는 먼저 err에 대입하고, 그다음 지연된 함수가 그것을 감쌉니다. 자세한 내용은 defer에 있습니다.

이름 있는 결과 섀도잉

이름 있는 결과는 함수의 가장 바깥 스코프에 있습니다. 중첩된 블록 안의 :=는 같은 이름의 새 변수를 만들고, 그러면 값 없는 return은 바깥 변수를 반환합니다.

func find() (n int, err error) {
	if true {
		n, err := compute() // new n and err, shadowing the results
		_ = n
		_ = err
	}
	return // returns 0, nil
}

최악의 경우는 컴파일러가 잡아 줍니다. 결과가 섀도잉된 블록 안의 값 없는 returnresult parameter err not in scope at return으로 실패합니다. 하지만 위 코드처럼 return이 블록 밖에 있는 경우는 잡지 못합니다. 결과 변수를 의도했다면 := 대신 =를 쓰세요.

흔한 실수

  • err가 nil이 아닌데 값을 사용함. err부터 확인하세요. 함수는 오류와 함께 쓰레기 값을 반환해도 됩니다.
  • 타입이 있는 nil 포인터를 error로 반환함. var e *MyErr; return e는 nil이 아닌 error를 반환합니다. 성공했을 때는 리터럴 nil을 반환하세요.
  • 결과가 너무 많음. 의미가 제각각인 결과가 셋 이상이면 쓰기 어렵습니다. 대신 구조체를 반환하세요.

자주 묻는 질문

Go 함수에서 여러 값을 반환하려면 어떻게 하나요?

결과 타입을 괄호 안에 나열하고, 값을 쉼표로 구분해 반환합니다: func minMax(xs []int) (int, int) { ...; return lo, hi }. 호출하는 쪽은 한 번에 모두 받습니다: lo, hi := minMax(nums).

Go에서 반환 값 중 하나를 무시하려면 어떻게 하나요?

빈 식별자 _에 대입합니다: _, err := strconv.Atoi(s) 또는 n, _ := strconv.Atoi(s). 값을 아예 빼 버릴 수는 없습니다. 왼쪽 변수 개수가 결과 개수와 같아야 합니다.

Go에서 이름 있는 반환 값이란 무엇인가요?

func split(n int) (half, rest int)처럼 이름이 붙은 결과 매개변수입니다. 제로 값으로 시작하고, 본문에서 대입할 수 있으며, 값 없는 return은 현재 값을 반환합니다. 지연된 함수가 호출자가 받을 값을 바꿀 수 있게도 해 줍니다.

Go에서 naked return을 써도 되나요?

짧은 함수에서만 쓰세요. 긴 함수의 값 없는 return은 무엇이 반환되는지 숨기고 섀도잉 버그를 쉽게 만듭니다. Go 스타일 가이드는 문서화를 위해 결과에 이름을 붙이되, 몇 줄이 넘는 함수에서는 값을 명시해 반환하라고 권합니다.

Coddy programming languages illustration

Coddy로 코딩 배우기

시작하기