14.3. 프로그램언어 고(Go)에서의 nil 포인터와 포인터 비교

프로그램언어 고(Go)의 nil 포인터 이해와 사용법

고(Go)언어의 nil 포인터에 대해 설명드리겠습니다.

var pointer *int
if pointer == nil {
    fmt.Println("nil 포인터입니다") 
}

고(Go)언어에서 nil은 포인터가 아무것도 가리키고 있지 않다는 것을 의미합니다. 위의 예제코드에서 pointer 변수는 *int 타입의 포인터 변수인데, 초기값이 nil입니다.

따라서 이 포인터 변수를 사용하려면 먼저 make나 new와 같은 함수를 사용하여 실제 메모리 공간을 할당받은 뒤에 사용해야 합니다. 그렇지 않으면 nil 포인터에 접근하여 파닉(panic)이 발생할 수 있습니다.

var pointer *int 
if pointer == nil {
    pointer = new(int)
} 
*pointer = 100

위의 예제에서는 pointer가 nil일 경우, new(int) 함수를 사용하여 int 타입의 메모리 공간을 할당받고 이 주소를 pointer 변수에 저장합니다. 이후 이 주소를 통해 값을 저장하거나 읽을 수 있습니다.

따라서 고(Go)언어에서는 포인터 변수를 사용하기 전에 nil인지 확인하는 것이 안전한 코딩 관행입니다. 특히 함수의 반환 값이 포인터일 경우 nil 체크가 필요합니다.

이 외에도 인터페이스, 슬라이스, 맵 등도 nil 값을 가질 수 있기 때문에, 역시 nil 포인터 파닉을 예방하기 위해 반드시 확인이 필요합니다.

프로그램언어 고(Go)에서의 nil 포인터 활용 시 주의점

프로그램언어 고(Go)에서 nil 포인터를 활용할 때 주의할 점들이 있습니다.

nil 포인터는 값이 없음을 의미하는 특별한 포인터 값입니다. Go 언어에서는 nil 포인터가 있는 변수를 사용하려고 하면 런타임 패닉(runtime panic)이 발생할 수 있습니다.


var p *int
fmt.Println(*p) // 런타임 패닉 발생 

위 코드에서 p 변수는 nil 포인터입니다. 여기서 p의 값을 접근하려고 하면 런타임 패닉이 발생합니다.

nil 포인터에 접근하면 프로그램이 크래시가 날 수 있기 때문에, 항상 nil 체크를 해주는 것이 좋습니다.


if p != nil {
  fmt.Println(*p) // p가 nil이 아니면 접근 가능
}

위 코드처럼 p가 nil인지 확인한 후에 접근하는 것이 안전한 코딩 방식입니다.

또한 Go 언어에서는 nil 인터페이스에 접근해도 에러가 발생할 수 있습니다.


var i interface{}
i.Method() // panic

인터페이스 i가 nil이기 때문에 메서드를 호출하면 패닉이 일어납니다.

인터페이스의 경우 type assertion을 이용해 nil이 아닌지 확인한 후 사용하는 것이 좋습니다.


if i != nil {
  i.Method() 
}

이처럼 Go 언어에서는 nil 포인터나 nil 인터페이스를 접근하면 위험할 수 있습니다. 그러므로 항상 nil 체크를 하고 사용하는 것이 중요합니다. 주의깊게 코딩하시기 바랍니다.

프로그램언어 고(Go)에서의 포인터 간 비교 방법

프로그램언어 고(Go)에서 포인터간 비교를 하는 방법은 주로 == 연산자를 사용합니다.


package main

import "fmt"

func main() {
    
    var a *int = new(int)
    *a = 10
    
    var b *int = new(int)
    *b = 20
    
    if a == b {
        fmt.Println("a와 b는 같은 주소를 가리킵니다") 
    } else {
        fmt.Println("a와 b는 다른 주소를 가리킵니다")
    }
}

위 예제코드에서 a와 b는 서로 다른 int형 변수를 가리키는 포인터 변수입니다.
*a = 10과 *b = 20에서 실제 값은 다르지만 가리키는 주소가 다릅니다.

따라서 위 조건문의 결과는 “a와 b는 다른 주소를 가리킵니다” 가 출력됩니다.

즉, 포인터간 비교 시 실제 값이 아닌 가리키고 있는 메모리 주소를 비교합니다.
== 연산자를 통해 주소 값이 같은지 다른지 판별할 수 있습니다.

예제에 주석을 달아서 더 자세히 설명하자면,


package main

import "fmt"

func main() {

    // int형을 가리키는 a 포인터 변수 선언 및 초기화
    var a *int = new(int) 
    
    // a가 가리키는 변수에 10 대입
    *a = 10
    
    // int형을 가리키는 b 포인터 변수 선언 및 초기화
    var b *int = new(int)
    
    // b가 가리키는 변수에 20 대입
    *b = 20
    
    // a와 b의 메모리 주소 비교
    if a == b {
        fmt.Println("a와 b는 같은 주소를 가리킵니다")
    } else {
        fmt.Println("a와 b는 다른 주소를 가리킵니다") 
    }
}

이와 같이 포인터 변수 a와 b를 선언/초기화하고 실제 값은 다르지만 주소가 다르기 때문에
“a와 b는 다른 주소를 가리킵니다”가 출력되는 것을 확인할 수 있습니다.

포인터간 비교 시 주소 비교에 유의하시기 바랍니다.

프로그램언어 고(Go)에서의 nil 포인터와 일반 포인터 간 비교

고(Go)언어에서의 nil 포인터와 일반 포인터 비교에 대해 설명드리겠습니다.

고(Go)언어에서 포인터는 메모리 주소를 가리키는 변수입니다. 포인터에 nil 값이 저장되면 그 포인터는 어떤 메모리 주소도 가리키지 않는다는 의미입니다.


package main

import "fmt"

func main() {
  var ptr1 *int
  var ptr2 *int = new(int)
  
  if ptr1 == nil {
    fmt.Println("ptr1은 nil 포인터입니다") 
  }
  
  if ptr2 != nil {
    fmt.Println("ptr2은 일반 포인터입니다")
  }
}

위의 예제코드에서 ptr1은 nil 포인터이고, ptr2는 일반 포인터입니다.

nil 포인터와 일반 포인터를 비교할 때 ==와 != 연산자를 사용합니다. ptr1 == nil은 ptr1이 가리키는 값이 없다는 의미이고, ptr2 != nil은 ptr2가 메모리 주소를 가리킨다는 의미입니다.

즉, nil 포인터는 아무것도 가리키지 않지만, 일반 포인터는 메모리 주소를 가리킵니다. 따라서 이 둘을 비교할 때 주의가 필요합니다.

nil 포인터를 역참조하면 런타임 패닉(runtime panic)이 발생하므로, 포인터가 nil인지 확인 후에 역참조를 해야 합니다.

이상으로 고(Go)언어에서의 nil 포인터와 일반 포인터 비교에 대해 간략히 설명드렸습니다. 포인터 개념을 잘 이해하시고 비교 시 유의하시기 바랍니다.

프로그램언어 고(Go)에서의 포인터 비교를 통한 오류 제어

고(Go)언어의 포인터 비교를 통한 오류 제어에 대해 설명드리겠습니다.

고(Go)언어에서 포인터 변수를 사용하다 보면 nil 포인터에 접근하여 파닉(panic)이 발생하는 경우가 있습니다. 이를 방지하기 위해 포인터 변수의 값이 nil인지 확인하는 것이 좋습니다.


package main

import "fmt"

func main() {

    var ptr *int
    if ptr == nil {
        fmt.Println("ptr is nil") 
        return
    }
    
    // ptr이 nil이 아닐때 할 일
    *ptr = 100 
}

위의 코드에서 ptr 포인터 변수는 nil값입니다.
따라서 if문에서 ptr==nil로 확인 후 nil일 경우 할당이나 참조하는 코드를 진행하지 않고 바로 return합니다.

이렇게 포인터가 nil인지 여부를 확인하는 것이 중요합니다. 특히 함수에서 리시버(receiver)나 매개변수로 포인터를 사용할 때 정상적으로 nil 체크를 해주지 않으면 nil 포인터 참조에 의한 런타임 패닉이 발생할 수 있습니다.


package main

import "fmt"

type user struct {  
    name string
    email string
}

func (u *user) print() {
    if u == nil {
        fmt.Println("user pointer is nil")
        return 
    }
    
    fmt.Println(u.name, u.email)  
}

func main() {
  
    var u *user
    
    u.print()
} 

print() 메서드의 리시버로 사용된 u포인터가 nil일수 있으므로 메서드 내에서 nil 확인 후 처리하는 것이 안전합니다.

이처럼 고(Go)언어에서는 포인터의 nil 확인이 중요하며, 이를 통해 nil 포인터 에러를 사전에 방지할 수 있습니다. 포인터 사용 시 코드의 안정성을 위해 nil 체크를 권장합니다.

Leave a Comment