본문 바로가기
프로그래밍/Go

고(Golang) | 튜토리얼 01 | 나도 모르게 고급 개발자 시리즈 | 패키지(package)와 import 구문

by K-인사이터 2023. 2. 16.
반응형

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

이전 튜토리얼 살펴보기

  1. 5분 만에 Golang 개발 환경 세팅하기

서론 

안녕하세요 K-IN입니다. 

"나도 모르게 고급 개발자 시리즈" 두 번째 시간입니다. 

이전 튜토리얼에서 Go 언어 개발 환경을 구성해 보았습니다. 

이번 시간에는 본격적으로 Go 언어의 특징을 살펴보도록 하겠습니다. 


본론

이 튜토리얼은 아래의 내용을 담고 있습니다.

  • 패키지의 개념과 import 구문

Go 언어 패키지(package) 핵심 정리

설명에 앞서 패키지와 import 가 Go 언어에서 의미하는 바를 설명드립니다. 

모든 Go 프로그램은 패키지(package)로 이루어져 있습니다. 

 

앞으로 여러분이 작성하게 될 코드의 대부분은 package main으로 시작할 것입니다. 

여기서 main 이란 프로그램의 시작 영역을 의미합니다.

 

다시말해 Go 가 실행할 코드의 시작점(entpry point)을 지시하는 역할을 합니다. 

백문이불여일견이죠. 간단한 프로그램을 살펴보겠습니다. 

package main // (1) 패키지 이름 지정 

import (
	"fmt"
	"math/rand"
)

func main() { // (2) 프로그램 시작 지점
	fmt.Println("로또번호를 알려줘", rand.Intn(10))
}

아주 간단한 프로그램이 만들어졌습니다.

이 코드를 main.go라고 지정해서 파일에 저장합니다. 

이제 여러분이 원하는 핵심 정리 들어가겠습니다. 

 

우리의 목적은 Go 프로그램이 실행되도록 하는 것입니다. 

이를 위해 지켜야할 두 가지가 있습니다. 

  1. 프로그램이 실행되기 위해서 main 패키지를 지정해야 한다. 
  2. main 패키지 내에 main 함수가 정의되어야 한다. 

아주 심플하면서 간단한 원칙입니다. 

이제, 두 가지 약속을 어기면 어떻게 되는지 보겠습니다. 

 

main 패키지를 지정하지 않은 경우 발생하는 에러를 살펴볼까요?

ㄴ package OOOO is not a main package

main 패키지가 없는 상태

main 함수를 지정하지 않은 경우 발생하는 에러를 살펴볼까요? 

runtime.main_main·f: function main is undeclared in the main package

main 함수를 지정하지 않은 경우

여기서 팁은 main 패키지와 main 함수를 모두 지정하지 않은 경우입니다. 

이 경우 당연히 상위 개념인 패키지 관련 에러가 발생합니다. 

 

그렇다면 패키지(package)는 어떻게(How) 정의(define)하고 쓸(use)까요? 

여러분은 이미 패키지를 사용하는 방법에 대해 알고 있습니다.

바로 fmt, math/rand 패키지가 바로 그것이고 여기에 힌트(hint)가 있습니다. 

import (
	"fmt"
	"math/rand"
)

math/rand 는 임의의 랜덤한 숫자를 출력하는 패키지입니다. 

여러분과 제가 매주하는 로또 숫자를 뽑아주는 역할입니다. 

 

조금 복잡한 화면을 보겠습니다. 

그림의 상단 -> 좌측 -> 우측 순으로 설명을 하겠습니다.

 

상단

우리가 사용한 math/rand 는 파일 시스템 상에서 볼때 디렉터리(폴더)의 경로입니다. 

좌측

그리고 rand 라는 폴더 하위는 모두 rand 라는 패키지 이름을 정의합니다. 

우측

rand 폴더 하위의 모든 파일(_test.go 파일들은 제외)들은 모두 rand 패키지입니다. 

위의 특징을 아래와 같이 간추려 정리할 수 있습니다. 

  • 우리가 사용하는 패키지는 폴더의 이름이다. 
  • 그 폴더 하위에서 동일한 패키지 이름을 가진 여러 파일들을 생성할 수 있다. 

자 이제 여러분은 두 가지 핵심 개념을 챙겼습니다. 

패키지란 무엇이고 그리고 어떠한 특성을 지녔는지를 알게되었습니다. 

 

다음으로 import 구문에 대해 살펴보겠습니다. 


쉬어가는 광고타임

코딩에 있어서 제일 중요한 것은 좋은 환경입니다. 저는 항상 작업을 할 때 애플 제품을 사용하고 있습니다. 

애플 제품은 제품들 끼리 모아두면 시너지가 두세배가 된다고 합니다. 

편안한 환경에서 조용한 음악과 함께 코딩을 하면서 지적인 작업을 해나가는 여러분의 모습이 대견합니다. 

사진: Unsplash 의 Dave Weatherall

Apple 2020 맥북 에어 13, 스페이스 그레이, M1, 256GB, 8GB, MGN63KH/A, MAC OS Apple 2022 에어팟 프로 2세대 블루투스 이어폰, 화이트 Apple 에어팟 맥스 블루투스헤드셋, 스페이스 그레이 Apple 2021 맥북프로 14, 스페이스그레이, M1 Pro 8코어, GPU 14코어, 512GB, 16GB, MKGP3KH/A, MAC OS Apple 정품 아이폰 14 Pro 자급제, 스페이스블랙, 256GB Apple 2022 맥스튜디오, M1 Max 10코어, GPU 24코어, 32GB, 512GB


Go 언어 핵심정리 Import 구문

import 란 무엇가를 들여오다라는 의미를 내포합니다. 

즉, 다른 사람 혹은 내가 만든 패키지들을 가져온다는 것을 의미합니다. 

 

만약, 여러분의 친구가 멋진 프로그램을 만들었을 때 이를 여러분도 사용하길 원할 것입니다. 

이때 import 는 친구의 코드를 가져오는 역할을 합니다. 

 

우선, import 를 사용하는 방법을 알아야겠죠? 

// 이렇게도 쓸수 있고 
import "fmt"
import "math"

// 이렇게도 쓸수 있습니다. 
// 이 패턴이 주로 사용됩니다. 
import (
	"fmt"
	"math"
)

 

자 그렇다면 친구의 입장에서 볼까요? 

친구는 여러분에게 제공하고 싶은 코드가 있고 숨기고 싶은 코드가 있을 것입니다. 

 

우선 폴더를 한번 생성해볼까요? 친구니까 friend 가 좋겠죠

우선 기억해야할 사항을 몇 가지 나열합니다. 매우 중요한 규칙들이니 기억해야 합니다. 

  1. 폴더(=디렉토리)의 이름은 패키지의 이름과 반드시 일치할 필요는 없습니다.
  2. 그러나 같은 폴더 내에 다른 패키지 이름이 올 수 없습니다. 
  3. 폴더 내에 또 폴더를 만들어 다른 패키지를 만들 수 있습니다. 
  4. 다른 패키지를 사용하려면 이름이 중요합니다. 반드시 대문자로 선언해야 합니다. 
  5. 같은 패키지라면 import 를 이용하지 않고 사용할 수 있습니다. 

자 이제 한번 예시들을 살펴보면서 내용을 정확히 이해도록 합시다. 


핵심원리 1. 폴더(=디렉토리)의 이름은 패키지의 이름과 반드시 일치할 필요는 없습니다.

만간을 이용해 프로젝트를 세팅하는 방법을 다시 반복해볼까요? 

아래의 코드를 따라 작성하면됩니다. 

mkdir tuts02
cd tuts02
go mod init k-in.com/tuts02
touch main.go

main.go 는 main 패키지입니다. 코드는 아래를 작성해주세요.

package main

import "fmt"

func main() {
  fmt.Println("Hello World")
}

자 이제 정민 친구가 작성한 코드를 가져와 보겠습니다. 

mkdir jungmin
touch hello.go

정민 친구는 hello.go 파일에 아래와 같이 작성했네요. 정겨운 친구의 대화입니다. 

package hello

import "fmt"

var mynameis = "정민"

func HelloMyFriend() {
	fmt.Println("안녕 친구야 ~ ")
}

func WhatIsYourName() string {
	return mynameis
}

main.go 파일로 돌아가 친구와 이야기해봅시다. 여기서 기억할 것은 한 가지입니다. 

폴더를 만들 때 "go mod init k-in.com/tuts02" 명령어를 사용했습니다.

즉, 폴더 내에 있는 모든 패키지 이름은 "k-in.com/tuts02" 입니다. 

 

main.go 파일의 변화를 살펴봅시다. 

  • hello "k-in.com/tuts02/jungmin" 이라는 이름을 작성해야 합니다. ·········· (1)
  • 그리고 hello.HelloMyFriend() 라는 함수를 호출(call)합니다.          ·········· (2)
package main

import (
	"fmt"

	hello "k-in.com/tuts02/jungmin" // (1) 이름이 요상하죠?
)

func main() {
	fmt.Println("Hello World")
	hello.HelloMyFriend() // (2) 이것은 함수입니다. 
}

 

폴더의 구조는 이렇습니다. 또한, jumgmin 폴더 이름에 hello.go 를 파일을 복사했고 패키지 이름은 hello 입니다. 

따라서, 아래와 같이 기억합니다. 

import [1. 패키지 이름] "[2. 패키지 생성 때 입력한 이름]/[3. 폴더명]"

  • [1. 패키지 이름] 은 정민이가 준 파일을 보니 "hello" 입니다. 
  • [2. 패키지 생성 때 입력한 이름] 은 처음에 우리가 첫 폴더를 만들 때 go mod init "k-in.com/tuts02/jungmin" 의 그 이름입니다.
  • [3. 폴더명] 은 정민이가 준 파일을 옮겨 놓은 폴더의 이름 "jungmin" 입니다. 

그렇다면, 정민이가 준 소스의 패키지 이름을 바꾸면 어떻게 될까요? 

정민이가 준 hello.go 의 패키지 이름을 jungmin 으로 바꾸었습니다. 친구의 이름을 코드에 남기기 위해서이죠.

아래의 코드는 모두 잘 동작합니다. 

그림을 왼쪽부터 1번이라고 지정하고 설명해볼께요. 

  • 1번 그림 - 패키지 이름을 변경 (hello -> jungmin)
  • 2번 그림 - alias 없이 패키지를 임포트 (hello 가 사라짐)
  • 3번 그림 - alias 를 사용해서 jungmin 패키지 이름을 바꾸어 사용 (hello 를 그대로 유지)

1번 그림 처럼 코드를 변경한 뒤에도 여전히 코드가 잘 동작할 것입니다.

이는 alias 라는 개념 때문입니다. alias 는 별명이라는 뜻이 있습니다. 

 

즉, 패키지에 다른 이름을 붙여주는 것이죠.

정민이는 항상 인사를 "헬로~"라고 하기에 친구들이 정민이를 헬로라고 부르기도 한답니다. 

 

이제, 패키지에 별명(alias)을 붙이고 친구의 소스코드도 가져와서 사용하는 방법을 익혔습니다. 

이것을 응용하면 미국에 있는 제임스랑 코드를 교환할 수도 있겠네요. 

깃헙 등을 이용하면 가능합니다. 이것은 나중에 필요하면 다루어볼게요. 


쉬어가는 광고타임

편안한 코딩 환경의 중요성을 강조 드렸습니다.

그러나! 애플 노트북은 주식 투자나 다른 프로그램과 호환이 안될 때가 많습니다.

요즘은 많이들 애플을 사용하고 있으니 그래도 덜하긴 하지만 당장에도 회사 업무를 볼 때는 윈도우 노트북을 많이 쓰니까요. 

 

호환성과 가성비를 중요시하는 현명한 소비자인 여러분께 직접 엄선한 노트북을 소개해드립니다. 

사진: Unsplash 의 Andreas Klassen

Apple 2021 맥북프로 14, 스페이스그레이, M1 Pro 8코어, GPU 14코어, 512GB, 16GB, MKGP3KH/A, MAC OS LG 그램 16인치 17인치 11세대 i7 512G RAM16G 일반 2IN1터치스크린 16Z90P 16T90P 17Z90P 노트북 윈도우포함, 16인치 터치스크린, WIN11 Home, 16GB, 512GB, 코어i7, 블랙 삼성전자 2021 노트북 플러스2 15.6, 퓨어 화이트, 셀러론, NVMe128GB, 8GB, WIN10 Pro, NT550XDA-K14AW 삼성전자 2022 갤럭시북2 39.6cm, WIN11 Home, 그라파이트, 16GB, 1TB, 코어i7, NT750XEW-A71AG 레노버 2022 씽크북 14 G4+ ARA, Arctin grey, 512GB, 라이젠7, 16GB, ThinkBook 14 Gen4+ ARA - 21D0000NKR, WIN11 Home 에이수스 2022 노트북 17.3, Mecha Gray, ASUS TUF Gaming A17 FA707RM-HX016, 라이젠7 5세대, 512GB, 8GB, Free DOS Apple 2021 맥북프로 16, 스페이스그레이, M1 Pro 10코어, GPU 16코어, 512GB, 16GB, MK183KH/A, MAC OS


핵심 원리 2.  같은 폴더 내에 다른 패키지 이름이 올 수 없습니다. 

정민이가 준 코드에 다른 코드를 넣어보겠습니다. 

정민이랑 작별인사를 할 때 쓰기 위한 코드입니다. 

파일을 생성하고 아래의 코드를 넣어 봅시다. 

cd jungmin
touch bye.go
package bye

import "fmt"

func Bye() {
	fmt.Println("Bye ~ ")
}

코드를 실행해볼까요? 

어랏 이상한 에러가 발생했네요. jungmin 폴더에 bye 랑 jungmin 패키지가 발견되었다는 에러입니다. 

main.go:6:2: found packages bye (bye.go) and jungmin (hello.go) in

네 맞습니다. 같은 폴더에는 동일한 이름의 패키지 이름만을 사용해야 합니다.

그렇지 않으면 Go 는 컴파일 하는 과정에서 에러를 발생시킵니다. 

 


핵심 원리 3. 폴더 내에 또 폴더를 만들어 다른 패키지를 만들 수 있습니다. 

정민이가 준 코드에 수경이가 준 코드를 넣어보겠습니다. 

참고로 수경이와 정민이는 중학교 2학년 때부터 단짝이었습니다. 

 

jungmin 폴더에서 sukyung 폴더를 만들어볼까요? 

그리고 friend.go 라는 파일을 만들어 봅시다. 

cd jungmin
mkdir sukyung
cd sukyung
touch friend.go

NiceToMeetYou 라는 함수를 작성하였습니다. 그리고 패키지 이름은 sukyung 입니다. 

package sukyung

import "fmt"

func NiceToMeetYou() {
	fmt.Println("난 수경이야 ~ 정민이랑 중학교 2학년때부터 단짝이었어~ ")
}

이제, main.go 파일을 조금 고쳐서 정민이와 수경이 모두에게 인사를 해봅시다. 

package main

import (
	"fmt"

	hello "k-in.com/tuts02/jungmin"
	"k-in.com/tuts02/jungmin/sukyung"
)

func main() {
	fmt.Println("Hello World")
	hello.HelloMyFriend()
	sukyung.NiceToMeetYou()
}

"go run ." 명령을 입력하니 잘 동작합니다. jungmin 폴더 내에 sukyung 이라는 새로운 폴더를 넣고 패키지 이름이 다른데도 불구하고 동작하는 것을 알 수 있습니다. 

어느새 폴더 구조가 복잡해졌네요. 하지만 Go 는 우리 예상대로 잘 동작해주고 있습니다. 


핵심 원리 4. 다른 패키지를 사용하려면 이름이 중요합니다. 반드시 대문자로 선언해야 합니다. 

수경이랑 대화를 좀 더 이어나가고 싶습니다.

그런데 아직 생일을 모르네요.

friend.go 파일을 조금 수정합니다. 

package sukyung

import "fmt"

var birthDay = "2003/12/12"

func NiceToMeetYou() {
	fmt.Println("난 수경이야 ~ 정민이랑 중학교 2학년때부터 단짝이었어~ ")
}

그리고 main.go 에서 수경이의 생일을 출력해볼까요? 

package main

import (
	"fmt"

	hello "k-in.com/tuts02/jungmin"
	"k-in.com/tuts02/jungmin/sukyung"
)

func main() {
	fmt.Println("Hello World")
	hello.HelloMyFriend()
	sukyung.NiceToMeetYou()
	fmt.Println("수경이 생일은 ", sukyung.birthDay)
}

에러가 발생했습니다. 분명 birthDay 변수를 선언했는데 말이죠.

아마 이 사실을 모른다면 여러분은 계속해서 코드의 오류를 찾아보았을 겁니다. 

그런데 이 오류는 좀 찾기 힘들죠. 왜냐 코드에 문제가 없기 때문입니다. 

 

Go 언어는 다른 패키지(sukyung)의 요소를 가져올 때 대문자로 시작하는 요소만 가져올 수 있습니다.

여기서 요소는 함수, 변수, 상수, 타입 등등이 모두 포함됩니다. 

이제서야 Go 소스들이 모두 대소문자가 번갈아가면서 작성된 이유를 알겠네요 ! 

friend.go 파일을 조금 고쳐 보겠습니다. birthDay 밑에 BirthDay (뻘스데이! 라고 강세를 실어서 발음해볼까요? ㅎㅎ) 라고 선언합니다. 

대소문자를 구분하니 오류는 없습니다. 

package sukyung

import "fmt"

var birthDay = "2003/12/12"
var BirthDay = "2003/12/12"

func NiceToMeetYou() {
	fmt.Println("난 수경이야 ~ 정민이랑 중학교 2학년때부터 단짝이었어~ ")
}

그리고 main.go 로 돌아와 sukyung.BirthDay 라고 고치면 코드가 다시 동작합니다. 

// 생략! 
func main() {
	fmt.Println("Hello World")
	hello.HelloMyFriend()
	sukyung.NiceToMeetYou()
	fmt.Println("수경이 생일은 ", sukyung.BirthDay)
}


핵심 원리 5. 같은 패키지라면 import 를 이용하지 않고 사용할 수 있습니다. 

자 길고 길었습니다. 오늘은 "핵심 원리 5" 까지만 하고 마칠 예정이니 좀더 참아주세요! 

그리고 광고 눌러주시는 것도 잊지 말구요. 선생님도 먹고 살아야 합니다 T..T

 

이제 수경이랑 정민이와 대화는 끝났으니 이제 제 소개만하면 됩니다. 

main.go 파일과 동일한 위치에 iam.go 파일을 만들어볼까요? 

폴더 구조가 복잡하니 아래 그림을 참고해주세요. 

 

// Filename: iam.go
package main

import "fmt"

func Hello() {
	fmt.Println("내 이름은 k-in 이라고 해 반가워 얘들아 ~ :D")
}

그리고 main.go 를 수정해주겠습니다. 

  • iam 은 main 패키지이므로 파일이 달라도 공유가 됩니다. 따라서 Hello() 함수를 호출만 하면됩니다. ········ (1) 
// 역시 생략 

func main() {
	fmt.Println("Hello World")
	hello.HelloMyFriend()
	sukyung.NiceToMeetYou()
	fmt.Println("수경이 생일은 ", sukyung.BirthDay)
	Hello() // (1)
}

쉬어가는 광고타임

노트북의 장기간 사용은 시력 저하 및 거북목 등의 질환으로 이어질 수 있습니다.

따라서, 장기간 노트북을 이용하기 보다는 1~2시간 주기로 자리에서 일어나서 스트레칭을 해주는 것이 좋습니다. 

 

혹시 최근 들어 갑자기 주변에서 인상을 찌푸리지 말라는 이야기를 듣고 계신가요? 

혹은 등이 너무 굽었다는 이야기를 듣고 계시지 않으신가요? 

 

만약, 이런 이야기를 들은 적이 있다면 외형적인 변화가 발생했다는 의미입니다. 

사람은 유기체이기 때문에 다시 원래로 되돌아가려면 많은 노력이 필요합니다. 

 

노트북 보다는 좋은 화질의 모니터를 통해 여러분의 자세를 바꾸고 큼직한 대화면으로 여러 창을 띄워 놓고 작업하시길 추천드립니다. 

사진: Unsplash 의 Jared Rice

한성컴퓨터 54.6cm FHD 프리싱크 리얼75 평면 모니터, ULTRON 2235V PLUS(일반) LG모니터 81.28cm모니터 컴퓨터모니터 32MN500MW IPS FHD LG전자 60.4 cm FHD 프리싱크 IPS 모니터, 24MK430H LG전자 68.6cm FHD 모니터 화이트, 27MN430HW [엘지전자] 27GQ50F 27인치 울트라기어 FHD 165Hz 게이밍모니터, LED Monitor (27GQ50F) 삼성전자 S24R35A LS24R35AFHKXKR 60.96cm 컴퓨터 모니터 삼성전자 F24T350 LF24T350FHKXKR 60.96CM 컴퓨터 모니터


결론

오늘 수업은 조금 길어졌네요. 

Go 언어에서 패키지의 개념과 import 구문에 대해서 배워 보았습니다. 

Go 와 관련해서 GOPATH, GOROOT 등의 복잡한 정보들이 인터넷에 범람하고 있습니다. 

하지만, 핵심은 매우 간단합니다. 

 

위에서 소개해드린 핵심원리만 기억하시면 앞으로도 헷갈리지 않고 Go 언어를 즐길 수 있습니다. 

 

이상으로 K-IN 이었습니다.

즐거운 하루되세요 

 

반응형