Golang - 배열, 구조체, 포인터

Lumi·2022년 2월 7일
0

Golang

목록 보기
6/38
post-thumbnail

🔥 배열

기존이 배열과 동일합니다.

var 변수명 [배열길이]타입

  • var a [5]int

초기화 하는 작업을 하고자 한다면

var a [3]int = [3]int{1,2,3}

좀더 특이한 배열의 활용법에 대하여 정리를 하였습니다.

var s = [5]int{1:10, 3:30}

이와 같은 코드는 index가 1이면 10, 3이면 30을 넣으라는 뜻 입니다.

var s = [5]int{0,1}

배열 갯수에 비해서 적은 수를 초기화 했다면 나머지 배열값들은 모두 초기값이 들어갑니다.

s := [...]int{10,20,30}

[...]의 의미는 들어오는 값에 맞는 길이를 가지겠다는 의미 입니다.
- 즉 이 코드에서는 3이 됩니다.
  • [...]같은 경우에는 뒤에 오는 값에 따라 길이가 고정이 되지만
  • []는 동적배열로 취급이 되기 떄문에 두 배열은 다른 배열을 의미하니다.
  • range

배열을 순회하는 역할을 합니다.

 t := [...]int{1,2,3,4,5}

for i, v := range t {
	fmr.Println(i,v)
}

이 코드를 보게 되면 이전에 사용했던 코드와 상당히 다른 부분이 많습니다.

  • 특히 for문

range를 통하면 배열의 경우에는 2개를 반환하게 되고 그 값은 모두 i, v에 들어가게 됩니다.

  • i = index, v = value

만약 index값이나 value값이 필요가 없다면 _를 사용하면 됩니다.

추가적으로 golang은 굉장히 강력한 언어 이기 떄문에 type이나 배열의 길이가 맞아야만 복사가 가능합니다.

이중배열

func main() {
	a := [2][5]int{
		{1, 2, 3, 4, 5},
		{6, 7, 8, 9, 10},
	}

	for _, x := range a {
		for _, y := range x {
			fmt.Println(y, " ")
		}
	}
}

이중배열을 통하여 순회를 하는 코드 입니다.

range, for등에 이해를 하였다면 손쉽게 접근이 가능합니다.

🔥 구조체

Solidity를 공부를 해봤고 사용을 해보았기 떄문에 이해하는데에는 많은 어려움이 없었습니다.

type 타입명 struct{
	~~~필드명
    // Name string
    // Class int
}

- 이후 해당 구조체를 사용하고자 한다면

var a 타입명

- 이런 방법으로 접근이 가능하다.

  • 많이 어렵지는 않지만 이런식으로 활용가능합니다.
  • 개인적으로 Solidity와 동일하게 사용이 가능하다고 생각이 듭니다.

만약 초기화와 동시에 값을 할당해 주고 싶다면

  • 이런방식으로도 활용 가능합니다.

물론 구조체 안에 구조체를 포함하여 작성도 가능합니다.

위에 있는 구조체 예시들은 모두 구조체 안에 type이 들어가 있지만 embeded field와 같이 타입을 따로 적지 않는 형식도 존재합니다.

type User struct{
	Name string
    ID string
    Age int
    Level int
}

type VIPUser struct{
	User
    Price	int
    Level 	int
}

이런식의 구조는 좀더 쉽게 접근 할수 있는 장점이 있습니다.

기존에는 Vip안에 있는 User의 Name에 접근을 하려면

VIPUser.User.Name

- 이런 방향으로 접근을 하였지만

- Embeded field를 사용하게 된다면

VIPUser.Name

- 이런 식의 접근이 가능합니다.

만약 VIPUser안에 Name이라는 변수가 존재한다면

VIPUser.Name으로 접근을 하게 되면
VIPUser안에 있는 Name이 나오게 됩니다.
- 즉 우선권은 기존에 잇는 변수에 있습니다.

구조체에 해당하는 내용은 아니지만 부수적으로 unsafe하는 패키지가 있습니다.

말 그대로 안전하지 않다는 뜻이로 안전하지 않는 방식의 함수를 제공합니다.

그중 대표적으로 unsafe.Sizeof(변수) 를 활용하여

해당 변수에 할당된 메모리의 크기를 확인가능합니다.

🔥 포인터

Node.js에서는 없는 개념이여서 좀더 집중해서 공부를 하였습니다.

포인터는 메모리 주소를 값으로 갖는 타입

일단 선언하는 방법에 대해서 간략하게 적어보면

var a int 

var p *int    // 포인터는 *을 붙입니다.

p = &a

변수가 선언이 되면 변수들은 각자 메모리 공간을 가지게 됩니다.
공간의 경우에는 모두 동일하게 주소값을 가지고 생기게 되지만 이후 공간에 크기 부분은 타입에 따라 달라지게 되고요

포인터는 이떄 주소값을 말합니다.

즉 a,b(포인터)가 있고
b = &a를 통해서 a의 주소값을 할당해 주게 되면

b의 주소값에는 a의 주소값이 값으로 담기게 됩니다.

또한 이렇게 포인트 변수로 선언된 값에는 주소값만이 할당이 될수 있지 다른 값을 할당할수 없습니다.

  • b = 20 == false!!!!

만약 값을 할당하고 싶으면

  • *b = 20 == true!!!
  • 이 의미는 b가 가지고 있는 공간을 의미하기 떄문에 가능합니다.

포인터는 *int(변수)와 같이 형변환을 지원하지 않습니다.

포인터를 쓰는 이유

우리는 값을 코드를 보고 예상을 할수 있지만 값이 원하는 값과 다르게 나왔습니다.

왜냐하면 함수에 인자로 들어가는 인자값들은 특정 값을 수정하지 않기 떄문입니다.

이게 무슨말이냐면

a = b 라는 코드를 생각해 보았을떄

우리는 a라는 변수에 b를 할당한다는 의미가 됩니다.

즉 이러한 구조에서 왼쪽에 있는 값은 값이 수정이 되는 것이고 오른쪽에 있는 값은 값을 주는 것과 같죠

함수에 인자로 들어가는 인자값들은 여기에서 오른쪽과 같은 역할을 하게 됩니다.

- 즉 값을 주는 역할만 할수 있지 값을 수정하는 역할은 할 수가 없습니다.

즉 data라는 변수를 함수를 통해 넘겨주게 되면 함수 내에서도 새로운 변수를 만들어 내서 해당 변수를 수정하게 됩니다.

  • 넘겨주는 변수가 아닌 새롭게 만들어진 변수를 바꿉니다.

이러한 문제를 해결하기 위해서 포인터가 사용이 되고 주소값을 받음으로써 해결이 가능합니다.

  • 즉 애초에 새로운 주소값을 만드는 방향으로 진행시키지 않으면 됩니다.

포인터 변수에 .을 찍게되면 해당 값에 접근이 가능합니다.

  • data.value == *arg.value 와 같은 표현 입니다.

new() 내장함수

구조체를 초기화하여 할당하는 방법입니다.

p1 := &Data{} 라는 코드가 있을떄 p1는 포인터 타입이고 Data는 구조체 입니다.

이런 코드는 바로 p1에 Data라는 구조체의 주소를 할당할수 있고 초기값 또한 {}안에 적어줌으로써 설정이 가능하고

후에는 p1을 통해서 조작이 가능합니다.

이와 같은 방식으로는

var p1 = new(Date)방법이 있습니다.

두가지 방식의 차이점은 초기값을 설정할수 있냐 없냐만이 존재합니다.

profile
[기술 블로그가 아닌 하루하루 기록용 블로그]

0개의 댓글