Multiple return values
Golang의 특징 중 하나는 function과 method가 여러 값을 return시킨다는 것이다. os 패키지의 Write method의 형식은 아래와 같다.
func (file *File) Write(b []byte) (n int, err error)
위 method에서 반환되는 값은 작성된 bytes 수(n)와, n != len(b) 일 때 non-nil 상태의 error를 반환한다.
Named result parameters
return 또는 해당 function 내 결과값은 named 될 수 있다. 또한 일반적인 변수로도 사용된다. named 되었을 때, 해당 타입에 따라 초기화가 수행된다. (int 라면 0) function에서 return이 수행되는 시점에서, 해당 인자의 값이 return 된다.
func nextInt(b []byte, pos int) (value, nextPos int) {
for ; i < len(b) && !isDigit(b[i]); i++ {
}
x := 0
for ; i < len(b) && isDigit(b[i]); i++ {
x = x*10 + int(b[i]) - '0'
}
return x, i
}
for i := 0; i < len(b); {
x, i = nextInt(b, i)
fmt.Println(x)
}
func ReadFull(r Reader, buf []byte) (n int, err error) {
for len(buf) > 0 && err == nil {
var nr int
nr, err = r.Read(buf)
n += nr
buf = buf[nr:]
}
}
Defer
Golang에서 defer 키워드는 function 내에서 return이 수행되기 직전에 수행된다. 이는 주로 resource의 해제나 mutex의 unlock 등에 주로 사용된다.
// Contents returns the file`s contents as a string
func Contents(filename string) (string, error) {
f, err := os.Open(filename)
if err != nil {
return "", err
}
defer f.Close() // f.Close will run when we`re finished.
var result []byte
buf := make([]byte, 100)
for {
n, err := f.Read(buf[0:])
result = append(result, buf[0:n]...) // append is discussed later.
if err != nil {
if err == io.EOF {
break
}
return "", err // f will be closed if we return here.
}
}
return string(result), nil // f will be closed if we return here.
}
defer을 사용하는 것은 아래와 같은 장점을 지닌다.
- 위 예시와 같이 file close 관련 구문을 실수로 작성하지 않는 경우를 보완해준다. 또한 return 구문 전에 중복으로 추가할 필요도 없다.
- open 구문 근처에 있으면, function의 끝지점에 file close 관련 구문이 있는 것 보다 더욱 명시적이다.
defer이 선언된 함수는 LIFO 순서를 따르게 된다. 아래의 코드는 4 3 2 1 0 과 같이 출력되고, 반환할 것이다.
for i := 0; i < 5; i++ {
defer fmt.Printf("%d ", i)
}
defer가 실행될 때 defer가 선언된 함수의 매개변수가 사용된다는 것을 이용할 수도 있다. 매개변수는 defer가 선언된 시점에 evaluated된다.
func trace(s string) string {
fmt.Println("entering:", s)
return s
}
func un(s string) {
fmt.Println("leaving:", s)
}
func a() {
defer un(trace("a"))
fmt.Println("in a")
}
func b() {
defer un(trace("b"))
fmt.Println("in b")
a()
}
func main() {
b()
}
--------------
entering: b
in b
entering: a
in a
leaving: a
leaving: b
'Development > Golang' 카테고리의 다른 글
[Effective Go] Control Structures (0) | 2021.11.20 |
---|---|
[Effective Go] Names (0) | 2021.11.20 |