본문 바로가기
Language/Go

Zero value

by ocwokocw 2022. 6. 17.

- 출처: https://dave.cheney.net/2013/01/19/what-is-the-zero-value-and-why-is-it-useful

- Zero value

내장 함수 new나 make를 호출하거나 선언을 통한 값을 저장하기 위해 메모리가 할당될 때, 명시적으로 초기화를 하지 않으면 메모리에는 기본 초기화된 값이 저장된다. 이때에는 해당 type에 맞는 zero value가 설정된다. boolean은 false, integer는 0, float은 0.0, string은 "", pointer, function, interface, slice, channel, map은 nil로 초기화된다. 초기화는 재귀적으로 일어나는데, struct 배열의 각 요소 인스턴스에는 값이 주어지지 않으면 해당 field의 zero value로 초기화된다.
 
default 값으로 설정되는 이런 특징은 프로그램의 정확성과 안전성 측면에서 중요하다.
 
아래 코드는 sync.Mutex를 사용하는 예제이다. sync.Mutex는 명시적인 초기화로직이 없어도 사용가능하도록 설계되어있다. sync.Mutex 내부에는 exported 되지 않은 2개의 integer field가 존재한다. zero value라는 개념 덕분에 sync.Mutex가 선언될때마다 0으로 설정된다.
 
package main

import "sync"

type MyInt struct {
        mu sync.Mutex
        val int
}

func main() {
        var i MyInt

        // i.mu is usable without explicit initialisation.
        i.mu.Lock()      
        i.val++
        i.mu.Unlock()
}
 
bytes.Buffer도 zero value를 사용한다. bytes.Buffer를 선언하면 명시적으로 초기화해주지 않아도 읽거나 쓰기를 시작할 수 있다. 아래 예제에서 io.Copy는 2번째 인자로 io.Reader를 받으므로 b에 대한 pointer를 넘겨줘야 한다.
 
package main

import "bytes"
import "io"
import "os"

func main() {
        var b bytes.Buffer
        b.Write([]byte("Hello world"))
        io.Copy(os.Stdout, &b)
}
 
slice는 zero value가 nil이다. zero value 덕분에 명시적으로 make를 통해 slice를 생성할 필요 없이 단순히 선언만 해도 된다.
 
package main

import "fmt"
import "strings"

func main() {
        // s := make([]string, 0)
        // s := []string{}
        var s []string

        s = append(s, "Hello")
        s = append(s, "world")
        fmt.Println(strings.Join(s, " "))
}
 
코드에서 var s []string 는 위에 코멘트 처리된 행들과 비슷하지만 완전히 동일하지는 않다. var s []string은 slice value가 nil 이지만 코멘트 처리된 행들은 slice value가 0의 길이를 갖는다는 차이가 있다.
 
아래 코드의 output은 false를 출력한다.
 
package main

import "fmt"
import "reflect"

func main() {
        var s1 = []string{}
        var s2 []string
        fmt.Println(reflect.DeepEqual(s1, s2))
}
 
nil pointer의 놀라운 점은 nil 값을 갖는 해당 type의 메소드를 호출할 수 있다는것이다. 아래 코드는 이런 특성을 기본값 제공에 활용한 예제이다.
 
package main

import "fmt"

type Config struct {
        path string
}

func (c *Config) Path() string {
        if c == nil {
                return "/usr/home"
        }
        return c.path
}

func main() {
        var c1 *Config
        var c2 = &Config{
                path: "/export",
        }
        fmt.Println(c1.Path(), c2.Path())
}
 
 

'Language > Go' 카테고리의 다른 글

package name base, util, or common  (0) 2022.06.26
Empty struct  (0) 2022.06.21
Error handling을 간단하게  (0) 2022.06.16
Exception  (0) 2022.06.14
Error handling  (0) 2022.06.12

댓글