[Go] Pointer, Array, Slice, Map, Struct

이한슬·2024년 1월 6일

Go

목록 보기
5/5

Pointer

다음과 같은 코드가 있을 때 b를 출력하면 어떤 값이 나올까?

  package main

  import "fmt"

  func main() {
  	  a := 1
      b := a
      a = 2
      fmt.Println(a, b)
  }

출력

2 1

b가 선언되는 시점에서 a에 저장되어 있던 1이 b에 저장되어 출력된다. 그래서 a는 2로 바뀌었지만, b는 그대로 1로 출력된다.

&

C처럼 메모리 주소에 접근할 수도 있다. 변수 앞에 &를 붙여 메모리 주소에 접근할 수 있다. &변수는 변수가 저장되어 있는 메모리 주소를 나타낸다.

  package main

  import "fmt"

  func main() {
  	  a := 1
      b := a
      fmt.Println(a, b)
      fmt.Println(&a, &b)
  }

출력

1 1
0x14000112008 0x14000112010

a와 b가 저장되어 있는 각각의 메모리 주소를 출력했다. b := ab에 a와 같은 값을 저장하는 것이지 a와 b가 같은 메모리 주소를 가지는 것이 아님을 알 수 있다.

*

이번에는 반대로 메모리 주소를 찾아가 값을 읽어보자. *을 사용하면 변수에 저장되어 있는 주소로 찾아가 그 값을 읽는다.

  package main

  import "fmt"

  func main() {
  	  a := 1
      b := &a
      fmt.Println(*b)	//(1)
      a = 2
      fmt.Println(*b)	//(2)
      *b = 3
      fmt.Println(a)	//(3)
  }

출력

1
2
3

(1) b에 a의 메모리 주소값을 저장하였고 *를 사용하여 b에 저장되어 있는 메모리 주소로 찾아가 그 값을 읽어 왔다. 즉, b에 저장되어 있던 a의 주소로 찾아가 a에 저장되어 있던 1을 읽어온 것이다.
(2) 그러므로 a를 2로 수정하고 나서 다시 *b를 출력해보면 b에 저장되어 있던 a의 주소로 찾아가 a에 저장되어 있는 바뀐 값인 2를 읽어오는 것이다.
(3) *b의 값을 변경해보면 b에 저장되어 있는 주소(a의 주소)로 찾아가 그 값(a의 값)을 3으로 변경하게 되면 a가 3으로 변경된다.

Array

go에서 배열을 만드려면 배열의 타입배열의 길이를 지정해주어야 한다.
[배열길이]배열타입{배열에 들어갈 값들...}과 같이 배열을 생성할 수 있다.
다음과 같이 배열의 길이를 미리 지정하고 나중에 값을 추가할 수도 있다.
아래에서는 배열의 길이가 3으로 지정되어있기 때문에 cafe[0~2]까지만 접근할 수 있다.

  package main

  import "fmt"

  func main() {
	  cafe := [3]string{"starbucks", "twosome"}
      cafe[2] = "hollys"
      fmt.Println(cafe)
  }

출력

[starbucks twosome hollys]

Slice

그렇지만 배열의 길이를 미리 지정하고 싶지 않을때도 있다. 그럴때는 slice를 사용할 수 있다.
slicearray에서 배열의 길이만 빠졌다고 생각하면 된다. []안에 배열의 길이를 쓰지 않고 비워둔다.
다만 slice를 사용할 때 값을 이후에 추가하고자 한다면 append() 함수를 이용한다. append 함수는 slice와 추가할 값을 인자로 받아, 새로운 값이 추가된 slice를 리턴한다. 그러므로 다음과 같이 hollys가 추가된 slice가 리턴되고, 이를 다시 cafe slice에 저장하여 출력시키면 된다.

  package main

  import "fmt"

  func main() {
	  cafe := []string{"starbucks", "twosome"}
      cafe = append(cafe, "hollys")
      fmt.Println(cafe)
  }

출력

[starbucks twosome hollys]

Map

map은 각각의 key와 그에 대응하는 value를 가지는 자료구조이다.
go에서 map은 다음과 같이 선언한다. map[key타입]value타입{key:value, key:value...}

  package main

  import "fmt"

  func main() {
	  starbucks := map[string]string{"name": "starbucks", "category": "cafe"}
      fmt.Println(starbucks)
  }

출력

map[category:cafe name:starbucks]

keyvalue를 모두 string 타입으로 정했기 때문에 keyvaluestring 이외의 타입을 넣게 되면 오류가 발생한다.

key와 value에 각각 접근할 수도 있다.

  package main

  import "fmt"

  func main() {
	  starbucks := map[string]string{"name": "starbucks", "category": "cafe"}
      for key, value := range starbucks {
          fmt.Println(key, value)
      }
  }

출력

name starbucks
category cafe

Struct

다른 언어에서의 object나 구조체와 비슷하게 go에서도 struct를 사용하여 자신만의 타입을 만들 수 있다.
type 구조체명 struct {필드명 필드타입}으로 선언하면 된다.

  package main

  import "fmt"
  
  type cafe struct {
      name	string
      discount	int
      payment	[]string
  }

  func main() {
  	  payment := []string{"cash", "card"}
	  starbucks := cafe{"starbucks", 10, payment}
      twosome := cafe{name: "twosome", discount: 20, payment: payment}
      fmt.Println(starbucks)
      fmt.Println(twosome.name)
  }

출력

{starbucks 10 [cash card]}
twosome

starbucks처럼 필드를 순서대로 입력하여 초기화할 수도 있지만 이렇게 초기화할 경우 직접 구조체 코드를 살펴보며 뭐가 뭔지 살펴야하기 때문에 웬만하면 twosome처럼 어떤것을 의미하는지 명확하게 적어주며 초기화하도록 하자.
이렇게 선언된 구조체 하위 필드는 twosome.name과 같이 접근할 수 있다.

profile
궁금하면 일단 먹어보는 소프트웨어 전공생

0개의 댓글