본문 바로가기
  • hazard_dev@__
  • hazard_dev@__
Go

[Go#6] Go언어 pointer, struct 문법!!!

by Hazard3_o00sung 2021. 1. 14.
728x90

구글의 강력한 오픈소스 언어 Go언어입니다

 

Powerful Concurrency Language Go

  고 언어는 기본적으로 C언어의 문법과 유사한 점이 많은 언어라는 점을 설명했습니다. 특히 포인터 변수와 구조체의 경우는 거의 동일하다고 보면 됩니다. C언어에 대해서 학습을 하신 분이 아니라면 포인터 변수에 대해서 잘 모를 수 있습니다. 아래 링크를 첨부해드릴 테니 아래 링크를 통해서 포인터 변수에 대해서 학습을 하고 오시고 오시면 될 것 같습니다. 

hazarddev.tistory.com/46

 

[C] 포인터 변수 자유자재로 사용하기!

Really Powerful Programming Language C 진짜 진짜 강력한 프로그래밍 언어 C언어의 포인터 변수에 대해서 설명하도록 하겠습니다!! 진짜 뭐 너무 강력해서 입이 다물어지지 않는 아주 완벽한 언어죠. 저도

hazarddev.tistory.com

Pointer Var

 

포인터 변수에 대해서 간략하게 알려드리자면, 한 변수 혹은 함수에 대해서 메모리 주소를 참조할 수 있게 해주는 메소드에 가깝습니다. 그러니까 아래 코드를 보면,

 

var i int = 10
pointerVar := &i

var p *int
p = &i

 

그러니까 포인터 변수가 아닌 일반적으로 선언된 변수의 메모리 주소 값을 참조하는 것이 포인터 변수입니다. 왜 이렇게 하냐는 분이 계실 텐데, 코드 상에서 코드 상 객체 혹은 데이터를 다룰 때, 원본 데이터의 무결성을 위해서 원본 객체 혹은 데이터를 참조하는 변수를 생성해 데이터를 수정하는 일이 빈번히 일어납니다. 그렇기 때문에 포인터 변수 같은 존재가 필요한 것입니다. 아래 코드를 통해서 알아보도록 하겠습니다.

 

package main

import "fmt"
import "reflect"

func main() {
	var foo int = 10
	var bar float64 = 3.14
	
	fooP := &foo;
	barP := &bar

	fmt.Println(*fooP);
	fmt.Println(*barP);
	
	fmt.Println(reflect.TypeOf(fooP))
	fmt.Println(reflect.TypeOf(barP))
}

 

reflect 패키지를 사용해서 타입을 확인해볼 예정입니다. 위와 같이 변수 두개가 선언되어 있으며, 아래에는 포인트 변수가 앞서 선언된 변수의 메모리 주소 값을 참조하는 포인터 변수가 됩니다. *가 붙으면 참조하는 값을 반환할 수 있지만, *가 붙지 않으면 그냥 메모리 주소 값이 반환됩니다. 

 

Struct Type

구조체는 C언어를 해보신 분이라면 다 아시겠지만 필드의 집합체라고 볼 수 있습니다. 필드라고 한다면, 구조체 내부의 선언된 필드를 의미합니다. 문법은 아래와 같이 사용할 수 있습니다.

 

type <*structname> struct { --- }

 

뭐 딱히 C언어와 다를 바가 없죠? 사용하는 측면에서도 그닥 다른 점은 없다고 봐도 무방합니다. 실제로 사용하는 에제 코드도 간단하게 보고 넘어가겠습니다.

 

package main

import "fmt"

type Foo struct{
	foo int
	bar int
}

func main() {
	fooSt := Foo{1,2}
	fmt.Println(fooSt)
	fmt.Println(fooSt.foo + fooSt.bar)
}

 

위처럼 구조체의 인스턴스를 생성할 수 있으며, 구조체 내부의 필드에는 '.'을 통해서 접근할 수 있습니다. 이외에도 C언어에서도 구조체 포인터 변수가 존재하듯이, 고 언어에서도 구조체 포인터 변수가 존재합니다. 사용방법은 간단합니다.

 

/* C Pointer to Struct Code */
#include <stdio.h>
#include <stdlib.h>

typedef struct Foo
{
	int foo;
	int bar;
}Foo;

int main()
{
	Foo foo;
	foo.foo = 1; foo.bar = 2;
	printf("foo : %d\t bar : %d\n", foo.foo, foo.bar);

	Foo *foo1 = malloc(sizeof(Foo));
	foo1->foo = 10;
	foo1->bar = 20;
	printf("foo : %d\t bar : %d\n", foo1->foo, foo1->bar);
	return 0;
}

 

C언어에서는 아시다시피 포인터 변수로 선언을 해주기 위해선 메모리를 정적으로 할당해준 다음 사용해야 한다는 것을 모두 알고 계실 겁니다. 하지만, 고 언어에서는 그런 것을 고려할 필요가 전혀 없습니다. 왜냐면 고 언어에서는 인스턴스를 만드는 순간 자동으로 메모리를 할당해주기 때문에, 뭐 이런 점들이 모여 C언어의 현대적인 버전 언어라는 말이 나오는 걸까요? 여하튼 고 언어 예제를 보도록 하겠습니다.

 

package main

import "fmt"

type Foo struct{
	foo int
	bar int
}

func main(){
	foo := Foo{10,20}
	fooP := &foo
	fmt.Println(*fooP)
	
	fmt.Println((*fooP).foo + (*fooP).bar)
}

 

이렇게 동적으로 구조체에 대한 메모리를 컴파일러 레벨에서 할당을 진행해주기 때문에 고려할 필요가 전혀 없죠. 그러고 아래를 보게 되면 fooP는 Foo인스턴스인 foo의 메모리 주소를 참조하는 것을 확인할 수 있습니다. 필드에 엑세스하기 위해선 제가 사용한 방식으로 접근을 해주면 됩니다!! 그리고 제가 이전 강의에서 설명드렸듯이, 고 언어에서는 값을 초기화하지 않으면 기본적으로 0 값이 들어가 있게 됩니다.  Struct Literals를 보면서 이해하도록 하겠습니다.

 

package main

import "fmt"

type Foo struct{
	foo int
	bar int
}

var(
	foo = Foo{1,2}
	foo1 = Foo{foo:1}
	foo2 = Foo{}
	foo3 = &Foo{3,4}
)

func main(){
	fmt.Println(foo,"\n", foo1, "\n", foo2, "\n", foo3);
}

 

구조체 리터럴은 필드에 있는 값을 나열해서 새로 할당되는 구조체 값을 나타낼 수 있습니다. 그러니까, 

 

foo:1

 

로 되어있는 부분을 볼 수 있습니다. 직접적으로 초기화할 수 있고 초기화가 이루어지지 않은 필드는 자동으로 0초기화 되는 것이죠, 그리고 &로 선언되어있는 foo3을 볼 수 있습니다. 구조체 값으로 포인터를 반환받는 키워드로 우리 이전에 배웠던 개념을 적용하면 됩니다!!

 

이상 구조체와 포인터에 대해서 학습해보았습니다!!! 다음 시간 때는 배열과 맵에 대해서 학습해볼 예정인데, 양이 방대하더라도 같이 할지 고려해서 업로드하도록 하겠습니다!!

 

읽어주셔서 감사합니다 😆😆😆😆😆

 

댓글로 피드백, 문의, 질문 모두 환영합니다!! ☺️☺️☺️☺️

 

 

다음 강좌 --->

hazarddev.tistory.com/71

 

[Go#7] Go언어 배열(Array_Slice, by Literal) 문법!

Powerful Concurrency Language Go 오랜만에 포스팅입니다! 그간 일이 너무 바빠서ㅜㅜ, 제일 중요한 자료구조 중 하나인 내장 자료구조 중 하나인! 배열에 대해서 학습해보도록 하겠습니다. 배열은 선형

hazarddev.tistory.com

 

728x90

댓글