IT/Develop

반응형


Go Lang의 메소드란 특정한 구조체에 연결되어 호출되는 함수를 의미합니다. 데이터와 코드를 묶어서 응집도를 높이기 위해 사용하는데, 응집도를 높여서 쓰는 것이 유리한 곳에 활용하기에 좋습니다. (통장 입출금 예제 등)

 

메소드의 형태 (함수와 유사하나 리시버 매개변수 추가 선언 필요)

 

func (리시버매개변수이름, 리시버매개변수타입) 메소드명() 리턴값 {
	구조체 멤버를 접근하여 연산수행 가능
}

 


 

메소드를 호출하기 위해서는 메소드를 호출할 값 다음에 . 을 이용하여 메소드를 붙여주면 됩니다. 이 때 메소드를 호출하는 값을 메소드 리시버(method receiver)라고 합니다.

 

메소드 형태를 참고하면서 다음과 같은 예제를 직접 작성해봅시다.

 

예제. 메소드 입출금 예제 만들어보기

 

package main

import "fmt"

type Account string

func (a Account) withdrawMethod() {
	fmt.Println("인출 메소드 실행 >", a) // 리시버 매개변수의 값 출력
}

func (a Account) depositMethod() {
	fmt.Println("입금 메소드 실행 >", a)
}

func main() {
	withdraw := Account("인출이 완료되었습니다")
	withdraw.withdrawMethod()
	deposit := Account("입금이 완료되었습니다")
	deposit.depositMethod()
}

 

출력결과물

 

인출 메소드 실행 > 인출이 완료되었습니다
입금 메소드 실행 > 입금이 완료되었습니다

 

리시버 매개변수의 이름은 원하는대로 사용하셔도 무방하나 하나의 타입에서 정의하는 모든 메서드는 가급적 동일한 리시버 이름을 사용해 가독성을 높이는 것이 좋습니다.

 


통장 입출금 예제를 사용해서 메소드에 대해 더 자세히 알아보도록 하겠습니다.

 

예제. 통장 입출금

 

package main

import "fmt"

type Account struct {
	balance int
}
	// 인출 함수
func withdrawFunc(a *Account, amount int) {
	a.balance -= amount
}
	// 인출 메소드
func (a *Account) withdrawMethod(amount int) {
	a.balance -= amount
}

func main() {
	a := Account{100} 
	b := Account{200}
	// 인출 함수 사용
	withdrawFunc(&a, 30)
	withdrawFunc(&b, 30)
	// 인출 메소드 사용
	a.withdrawMethod(40)
	b.withdrawMethod(50)

	fmt.Printf("%d, %d", a.balance, b.balance)
}

 

출력결과물

 

30, 120

 

메소드와 함수는 모습은 많이 유사하지만 분명한 차이점이 있습니다. 특히 위의 예제에서 인출 함수와 인출 메소드는 큰 차이가 없어보이도록 구성되어 있습니다.

메소드는 리시버 매개변수를 메소드 이름 앞에 작성해주고 호출할때는 리시버를 활용한다는 점에서 함수와의 차이점이 발생합니다.

 

Go Lang에서는 일반적으로 리시버 이름을 (a Account) 혹은 (d Deposit)과 같이 리시버 타입의 첫 번째 문자를 소문자로 사용합니다.

반응형
반응형


Go Lang의 구조체(Struct)는 필드를 하나의 개념으로 묶는 것을 의미합니다.

Go Lang에는 타 언어에서 사용하는 Class와 상속을 지원하지 않습니다. 대신 메소드를 구조체에 연결하는 방식을 통해 Class의 형태를 구현합니다. 이 경우 메소드는 구조체안에서 정의되는 것이 아니라 구조체 밖에서 정의되어 사용합니다.


우선 메소드에 대해 알아보고 구조체를 공부해봅시다.

 

Go Lang은 객체지향 언어가 아니기 때문에 메소드가 존재합니다.
Go Lang의 메소드란 특정한 구조체에 연결되어 호출되는 함수를 의미합니다. 데이터와 코드를 묶어서 응집도를 높이기 위해 사용하는데, 응집도를 높여서 쓰는 것이 유리한 곳에 활용하기에 좋습니다. (통장 입출금 예제 등)

 

메소드의 형태

 

func (구조체변수 구조체이름) 메소드명() 리턴값 {
	구조체 멤버를 접근하여 연산수행 가능
}

 

통장 입출금 예제를 사용해서 메소드에 대해 더 자세히 알아보도록 하겠습니다.

 

예제. 통장 인출 메소드 만들기

package main

import "fmt"

type Account struct {
	balance int
}

// 인출 메소드
func (a *Account) withdrawMethod(amount int) {
	a.balance -= amount
}

func main() {
	a := Account{100}
	b := &Account{200}
	// 인출 메소드 사용
	a.withdrawMethod(40)
	b.withdrawMethod(50)

	fmt.Printf("a계좌 : %d, b계좌 : %d", a.balance, b.balance)
}

 

출력결과물

 

a계좌 : 60, b계좌 : 150

 

출금메소드를 생성해서 a와 b 계좌에서 차감하는 예제를 간단히 만들 수 있습니다.


구조체의 형태

 

struct {
	field1 string
	field2 int
}

 

 

구조체 내부는 각각의 필드명과 필드 타입으로 구성됩니다.

 


 

예제. 구조체 만들기

 

package main

import "fmt"

type hero struct {
	name string
	age int
	weapon string
}

var h hero

func main()  {
	h := hero{}
	h.name = "유비"
	h.age = 30
	h.weapon = "자웅일대검"
	fmt.Println(h)
}

 

출력결과물

 

{유비 30 자웅일대검}

 

위의 예제는 person 구조체를 선언하고 그 구조체에 name과 age를 각각 타입 선언하였습니다. person 구조체 하에 변수 p 선언하고 이를 통해 name과 age의 필드값을 설정한 결과값을 출력하였습니다.

 


구조체 선언 후에 별도 함수를 생성해서 연결하는 것이 가능하고 매우 쉽고 간편합니다.

 

예제. 함수 연결하기

 

package main

import "fmt"

type hero struct {
	name string
	age int
	weapon string
}

var h hero

func main()  {
	h := hero{}
	h.name = "유비"
	h.age = 30
	h.weapon = "자웅일대검"
	fmt.Println(h)
	hero01()
    hero02()
}

func hero01()  {
	h.name = "관우"
	h.age = 31
	h.weapon = "청룡언월도"
	fmt.Println(h)
}

func hero02()  {
	h.name = "장비"
	h.age = 28
	h.weapon = "장팔사모"
	fmt.Println(h)
}

 

출력결과물

 

{유비 30 자웅일대검}
{관우 31 청룡언월도}
{장비 28 장팔사모}

 


 

위에서 보듯 구조체는 크기가 큰 경우도 많습니다. 이런 경우에도 함수는 전달된 인자의 복사본을 사용합니다. 필드가 많은 구조체의 경우 포인터를 통해 인자를 전달하는 것이 메모리 관리에 도움이 됩니다.

 

포인터 변수를 직접 출력하면 변수가 가리키는 메모리의 주소 값이 나옵니다. 포인터가 나타내는 주소값이 아닌 포인터의 값을 가져오려면 *를 사용합니다.

 

var i int = 12
var p *int = &i
var q *int = p
fmt.Printf("i의 주소 : %p\n", &i)
fmt.Printf("p의 주소 : %p, p의 값 : %p\n", &p, p)
fmt.Printf("q의 주소 : %p, q의 값 : %p\n", &q, q)

 

출력결과물

 

i의 주소 : 0xc0000140b0
p의 주소 : 0xc00000e028, p의 값 : 0xc0000140b0
q의 주소 : 0xc00000e030, q의 값 : 0xc0000140b0

 

i의 주소값이 p의 값이 되었음을 확인 가능합니다. p와 q 모두 값 자체는 동일하지만 각 포인터가 가리키는 주소값은 다름을 확인할 수 있습니다.

 


**이중 포인터를 활용해서 주소를 따라가라는 명령을 줄 수 있습니다.

 

var i int = 12
var p *int = &i
var q **int = &p
fmt.Printf("i의 주소 : %p\n", &i)
fmt.Printf("p의 주소 : %p, p의 값 : %p\n", &p, p)
fmt.Printf("q의 주소 : %p, q의 값 : %p\n", &q, q)

 

출력결과물

 

i의 주소 : 0xc0000140b0
p의 주소 : 0xc00000e028, p의 값 : 0xc0000140b0
q의 주소 : 0xc00000e030, q의 값 : 0xc00000e028

 

포인터를 너무 자주 사용하기보다는 규모가 큰 구조체나 변경이 필요한 구조체의 경우에 용이하게 사용하고, 슬라이스 맵 함수 등에는 내부적으로 포인터가 구현이 되어있으므로 굳이 쓰지 않아도 무방할 것입니다.

반응형

'IT > Develop' 카테고리의 다른 글

Go Lang 기초 13 - 인터페이스(interface)  (0) 2021.07.30
Go Lang 기초 12 - 메소드(Method)  (0) 2021.07.28
Go Lang 기초 10 - 맵(Map)  (0) 2021.07.28
Go Lang 기초 9 - 슬라이스(Slice)  (0) 2021.07.28
Go Lang 기초 8 - 배열(Array)  (0) 2021.07.28

Go Lang 기초 10 - 맵(Map)

2021. 7. 28. 19:53
반응형


Go Lang의 맵(map)은 잘 정리되어 있는 서류 문서함과 같습니다.

 

Go Lang의 맵은 저장된 값을 키(key)를 통해 접근할 수 있는 자료구조로, 키를 사용해 맵의 데이터를 편리하게 가져 올 수 있습니다.

 

맵(Map)에서의 선언 역시, 배열과 슬라이스와 유사한 형태를 가집니다.

 

var 맵이름 map[키type]값type   // 맵 변수의 선언
make(map[키type]값type       // 맵의 실제값 생성

 


예제. make함수를 활용한 맵 만들기

 

package main

import "fmt"

func main() {
	Greeting := make(map[string]string)
	Greeting["English"] = "Good morning!"
	Greeting["Français"] = "Bonjour!"
    
	fmt.Println(Greeting)
}

 

출력결과물

 

map[English:Good morning! Français:Bonjour!]

 

위의 예제를 통해 맵에 string타입 지정후, 영어 인사와 프랑스어 인사를 작성해보았습니다.

 


Go lang에서는 맵의 데이터를 간편하게 저장하고 조회할 수 있습니다.

 

예제. 맵의 데이터 저장 및 조회하기

 

package main

import "fmt"

func main() {
	var iMap map[int]int
   	iMap = make(map[int]int)
   	iMap[0] = 3
   	iMap[5] = 9
   	val, suc := iMap[3]
   	fmt.Println(iMap[0], iMap[5], iMap[3])
   	fmt.Println(val, suc)
}

 

출력결과물

 

3 9 0
0 false

 

위의 예제는 iMap에 0이 들어가면 3이 나오고, 5가 들어가면 9가 나오도록 구조를 만든 것 입니다.
맵의 데이터를 조회할 때는 리턴 값에서 두번째 자리(예제에서는 suc)에 키의 존재 여부를 확인하도록 저장되며 iMap에는 값이 없기 때문에 false가 뜨는 것을 확인할 수 있습니다.

 


이번에는 delete를 활용해서 예제 8에서 사용했던 인사 맵에 저장된 데이터를 삭제해보도록 합시다.

 

예제. 맵의 데이터 삭제하기

 

 

package main

import "fmt"

func main() {
	Greeting := make(map[string]string)
	Greeting["English"] = "Good morning!"
	Greeting["Français"] = "Bonjour!"

	delete(Greeting, "English")

	fmt.Println(Greeting)
}

 

출력결과물

 

map[Français:Bonjour!]
반응형

'IT > Develop' 카테고리의 다른 글

Go Lang 기초 12 - 메소드(Method)  (0) 2021.07.28
Go Lang 기초 11 - 구조체(Struct)  (0) 2021.07.28
Go Lang 기초 9 - 슬라이스(Slice)  (0) 2021.07.28
Go Lang 기초 8 - 배열(Array)  (0) 2021.07.28
Go Lang 기초 7 - 함수 func  (0) 2021.07.28
반응형


Go Lang의 슬라이스(Slice)는 값을 추가하여 확장가능한 자료구조로 크기가 고정되어 있지 않고 동적으로 배열의 크기를 증가시킬 수 있습니다.
슬라이스는 Go Lang 내장 함수인 make를 통해 공간을 확보할 수 있습니다.
make 함수는 (타입type, 길이length, 용량capacity)를 선언하여 사용합니다. 여기서 용량은 내부배열의 최대길이를 의미합니다.

 

슬라이스 선언은 배열(Array)과 거의 비슷합니다. 다만, []안에 길이 지정을 하지 않습니다.

 

var 변수명 [] 데이터타입

 

예제. 슬라이스 선언하고 길이와 용량 확인하기

 

package main

import "fmt"

func main() {
	s :=  []int{0, 1, 2, 3, 4, 5}
	l := len(s)
	fmt.Println(l, cap(s), s)
}

 

출력결과물

 

6 6 [0 1 2 3 4 5]

 

cap()은 배열의 기본 용량을 알려주고, len()은 배열에 몇 개의 항목이 있는지를 알려주는 함수입니다.
len(s)와 cap(s) 를 통해 슬라이스의 길이와 용량를 확인 할 수 있습니다.


make 함수를 사용해 슬라이스를 조금 더 자세히 다뤄보도록 합시다.

 

s := make([]int, 3, 3)

 

s는 정수형 타입에 길이가 3이고 용량 3인 슬라이스입니다.
슬라이스로 부터

 

s[0] = 1
s[1] = 2
s[2] = 3
fmt.Println(s[1])

 

각 원소자리에 값을 하나씩 지정해주고 출력을 해봅니다.

 

출력결과물

 

2

 


슬라이싱(Slicing)은 슬라이스의 특정 영역을 추출하는 기능입니다.

 

예제. 슬라이싱 해보기

package main

import "fmt"

func main() {
	s := make([]int, 3, 3)
	s[0] = 1
	s[1] = 2
	s[2] = 3
	t := s[0:3]
	u := s[:3]
	v := s[1:]
	fmt.Printf("t = %d, u = %d, v = %d", t, u, v)
}

 

출력결과물

 

t = [1 2 3], u = [1 2 3], v = [2 3]

 

슬라이싱의 경우 u는 0번 index부터 3번 index 바로 전까지, v는 2번째 index부터 마지막 index까지 슬라이싱 가능합니다.


예제. 슬라이스의 크기 자동조절 기능 확인하기

 

package main

import "fmt"

func main() {
	s := make([]int, 0, 3)
	for i := 0; i < 5; i++ {
		s = append(s, i)
		fmt.Printf("cap : %v, len : %v, add : %p\n", cap(s), len(s), s)
	}
}

 

 

출력결과물

 

cap : 3, len : 1, add : 0xc000016160
cap : 3, len : 2, add : 0xc000016160
cap : 3, len : 3, add : 0xc000016160
cap : 6, len : 4, add : 0xc000018120
cap : 6, len : 5, add : 0xc000018120

 

Go Lang의 슬라이스는 기본 배열의 크기를 자동으로 조절합니다.
append를 통해 추가한 값이 처음 설정된 용량을 넘어서면 더 큰 용량의 새 슬라이스를 반환합니다. 이 때 포인터 주소도 새로운 주소로 변경됩니다.

반응형

'IT > Develop' 카테고리의 다른 글

Go Lang 기초 11 - 구조체(Struct)  (0) 2021.07.28
Go Lang 기초 10 - 맵(Map)  (0) 2021.07.28
Go Lang 기초 8 - 배열(Array)  (0) 2021.07.28
Go Lang 기초 7 - 함수 func  (0) 2021.07.28
Go Lang 기초 6 - 반복문 For  (0) 2021.07.28
반응형


다른 여러 프로그래밍 언어들과 마찬가지로 Go Lang도 많은 데이터를 다루어야할 경우 사용할 수 있는 자료구조를 제공하고 있습니다.

그 대표적인 것들이 바로 배열(Array), 슬라이스(Slice), 맵(Map)입니다.

 

이번 시간에는 배열(Array)에 대해 알아보도록 하겠습니다.

 

Go Lang의 배열은 길이가 고정된 동일한 타입을 갖는 값을 순서대로 저장하는 자료구조입니다.

 

  • Go Lang의 배열에서 인덱스는 0부터 시작합니다.
  • 배열이 가지고 있는 각 값을 원소라고 하며 Go Lang의 정수형(int)과 문자열(string), 부동 소수점(float) 등 모든 타입에 대한 배열을 만들 수 있습니다.
  • 배열 선언은 대괄호[]를 통해 합니다.
배열의 형태
var 변수명 [배열크기] 데이터타입​

예제. 배열 만들기

package main

import "fmt"

func main() {
	var singleArray [3]int = [3]int {1, 2, 3}
	fmt.Println(singleArray)
}

 

출력결과물

[1 2 3]

위의 예제 6은 singleArray를 정수형의 3가지 원소를 가진 배열임을 선언하였고, 선언과 동시에 그 3가지 원소값을 1,2,3으로 초기값을 지정해준 예제입니다. 이처럼 배열의 초기값을 지정해주는 것을 배열 초기화라고 합니다.
대괄호[]안에 ...을 사용해 배열크기를 자동으로 지정해줄 수 있습니다.

 

아래의 식들은 결과적으로 동일한 의미를 나타냅니다.

 

var singleArray [3]int = [3]int {1, 2, 3}
var singleArray = [3]int {1, 2, 3}
var singleArray = [...]int {1, 2, 3}

 

singleArray 선언시에 반드시 타입을 지정해주지 않아도 되는 이유는 Go Lang이
R Value를 통해 L Value의 타입을 알 수 있는 언어이기 때문입니다.

다만,

 

var singleArray [3]int

 

까지만 지정해서 index 값을 지정해주지 않으면, 출력결과물은 [ 0 0 0 ] 이 됩니다.


예제. 다중 배열 만들기

 

package main

import "fmt"

func main() {
	var multiArray = [2][3][4]int{
		{{1, 2, 3},
			{1, 2, 3},
			{1, 2, 3}},
		{{1, 2, 3},
			{1, 2, 3},
			{1, 2, 3}},
	}
	fmt.Println(multiArray)
}

 

출력결과물

 

[[[1 2 3 4] [1 2 3 4] [1 2 3 4]] [[1 2 3 4] [1 2 3 4] [1 2 3 4]]]

 

위의 예제는 1,2,3,4의 [4]배열이 [3]개 있고, 그 [3]배열이 다시 [2]개 더 있는 형태입니다.


예제. 배열 초기화

 

package main

import "fmt"

func main() {
	var iArray = [10]int {
		5: 10, 9: 23,
	}
	fmt.Println(iArray)
}

 

출력결과물

 

[0 0 0 0 0 10 0 0 0 23]

 

배열의 index는 0부터 시작되기 때문에 5번째 index에 10이라는 정수값을 초기화해주려면 4: 10을 입력해야합니다. 위의 예제에서는 5: 10, 9: 23으로 초기화했으므로 10개의 원소 중 6번째와 10번째 값에 각각 10과 23이라는 값이 지정되었음을 확인할 수 있습니다.

반응형

'IT > Develop' 카테고리의 다른 글

Go Lang 기초 10 - 맵(Map)  (0) 2021.07.28
Go Lang 기초 9 - 슬라이스(Slice)  (0) 2021.07.28
Go Lang 기초 7 - 함수 func  (0) 2021.07.28
Go Lang 기초 6 - 반복문 For  (0) 2021.07.28
Go Lang 기초 5 - 조건문 Switch  (0) 2021.07.28

+ Recent posts