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

[Go#3] Go언어 패키지, import-export, function 이해하기!!!

by Hazard3_o00sung 2021. 1. 5.
728x90

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

 

Powerful Concurrency Language Go

  저희 저번 시간에는 고 언어의 변수의 타입과 타입 캐스팅에 대해서 알아보았습니다. 물론 만약 못 보신 분이 계시다면 아래 링크를 통해서 보고 오시는 것을 추천드립니다!! 물론 알고 계신다면 보고 올 필요가 전혀 없겠죠.

 

hazarddev.tistory.com/64

 

[Go#2] Go언어 변수_ 상수, 타입, 타입 캐스팅!!!

Powerful Concurrency Language Go 저번 시간에는 고 설치법 및 기본적인 사용방법에 대해서 알려드렸습니다. 만약 설치를 못하신 분이라면 아래 링크를 통해 설치를 하고 오시는 것을 추천드립니다!! haza

hazarddev.tistory.com

이번 시간에는 고 언어의 패키지와 간단한 함수 기능에 대해서 학습해볼 예정입니다. 

 

Package

모든 고 언어로 작성된 프로그램들은 패키지로 패킹됩니다. 그러니까 만약 아래의 코드가 있다면,

 

func main(){
	/*** code section ***/
}

 

main패키지안에서 프로그램 시작 영역이 지정되기 때문에 main패키지라 불러도 무방합니다. 블로그 글에 자주 나오는 fmt는 고 언어의 표준 라이브러리 패키지입니다. 이 또한 패키지라고 지칭하면 됩니다. 그 외에도 내장 패키지들이 많지만 자주 사용해볼 법한 패키지는 math패키지가 되겠죠? 

golang.org/pkg/math/

 

math - The Go Programming Language

Package math

math패키지 내부에 선언된 함수들과 간략한 설명들이 내포되어 있습니다. 그렇다면 이 중에서 저희는 아래 코드와 같은 코드를 작성해볼 예정입니다!

 

package main

import (
	"fmt"
	"math"
)

func main() {
	var foo int = 10
	var bar float64 = 20
	fmt.Println(math.Sqrt(bar))
	fmt.Println(foo)
}

 

만약 파이썬이었다면 아래 코드와 같이 타입에 관계없이 모두 동작합니다.

 

>>> import math
>>> a = 10
>>> b = 3.14
>>> c = 12.342342
>>> math.sqrt(a)
3.1622776601683795
>>> math.sqrt(b)
1.772004514666935
>>> math.sqrt(c)
3.513166947356758

 

하지만 고 언어는 타입에 매우 엄격합니다. 동적 및 정적 컴파일이 모두 가능한 언어이나, 기본적으로 타입이 지정된 함수의 인자라던지 그런 부분에 대해서는 엄격하게 변수의 타입을 맞추지 않으면 오류가 발생합니다. 이 부분은 모두 실습해보시길 바랍니다.

 

여하튼 이야기가 조금 한 바퀴 둘렀지만, 고 언어에서의 모든 것은 패키지라는 점을 잊지 마세요!! 

 

그리고 제가 지금 코드를 import ( --- )와 같이 임포트를 해주었습니다. 하지만 그거에 구애받지 않고 아래와 같은 코드를 사용해도 됩니다. 하지만 코드의 가독성을 위해서 하나로 묶어주는 것이 더욱 보기는 좋겠죠.

 

import math
import fmt

 

Export Naming Rule

고 언어에서 만약 우리가 어떤 패키지를 임포트 했다고 가정해봅시다. 예를 들어, math 우리가 배운 거니까요? 고 언어에서는 패키지는 소문자로 시작하나, 그 내부에 있는 속성을 사용할 때는 모두 대문자로 시작합니다. 이렇게 되면 뭐 아래와 같이 복잡하게 들쑥날쑥하는 일은 없겠죠.

 

//this is just sample code, not a go grammar
import math
math.sqrt() 
math.Abs()
math.Ceil()
math.cos()

 

네 엉망이죠? 어떤 함수는 소문자로 시작하고 어떤 함수는 대문자로 시작하고 가독성 측면에서 꽝이라고 볼 수 있습니다. 그래서 고 언어는 일련의 규칙이 있습니다. 패키지 내부의 속성을 export 될 때 대문자가 아닌 것은 패키지 외부에서 접근할 수 없습니다.

 

package main

import (
	"fmt"
	"math"
)

func main() {
	var foo float64 = -10.23
	fmt.Println(math.abs(foo))
}

 

위 코드에서 abs일 때는 당연히 오류가 발생합니다. 따라서 위의 규칙대로 대문자로 바꿔서 컴파일을 시도해보세요!! 지금은 왜 굳이 이렇게 까지라는 생각이 들 수 있으나, 나중에는 이름 하나하나가 모두 귀찮아집니다. 하나로 통일된 것이 얼마나 좋은데요!

 

Function on Go

프로그래밍 언어에서 빠질 수 없는 존재 함수죠. 여기선 느 간단하게 하고 넘어갈 예정이지만, 사실 함수는 계속해서 강의 글에서 계속 자주 등장해줄 예정이기 때문에, 한 번에 다 설명할 수도 없을뿐더러, 차근차근하고 넘어 가는 게 더 좋죠! 우선 고 언어에서의 함수는 아래와 같은 문법으로 구성됩니다.

 

func <*Function_Name*> (Args<arg_Type> ) <Return_Type> {
	// function block
}

 

고 언어에서의 함수 원형은 위와 같습니다. 함수의 인자는 개수가 얼마가 됐든 받을 수 있습니다. 솔직히 저도 어디까지 될지 모르겠으나, 이론 상 아주 많이 받을 수 있습니다. 그리고 함수의 인자는 타입이 선언되어야 하며, 중괄호 이전에 함수의 반환 타입을 선언하지 않으면 이 또한 컴파일 오류가 납니다. C언어와 비슷하다는 점을 유의해서 프로그래밍하면 되니 이런 점은 문제 될 것 없죠.

 

package main

import "fmt"

func addFoo(foo int, bar int) int {
	if (foo > bar){
		return foo + 10;
	} else if (foo < bar) {
		return bar + 5;
	} else {
		return foo + bar;
	}
}
func main() {
	fmt.Println(addFoo(10,20))
}

 

기본적으로 본 함수에는 두 개의 인자를 받습니다. 정수형 두 개를 받아서 정수형 타입을 반환하겠다는 것을 컴파일러에게 명시적으로 알려줍니다. 그리고 제어문을 통해서 결괏값이 반환되게 됩니다. 그러니까 프로그래밍 언어에서의 함수는 어떤 결과물을 만드는 통이라고 생각하면 됩니다. 우리가 중학교 때 배웠던 박스를 잘 생각해보면 됩니다. 박스가 있고 그곳으로 숫자가 들어오고 숫자가 나갑니다. 그러니까 함수라는 박스 내부의 로직을 통해서 계산된 결괏값을 반환하는 게 함수입니다. 모두 함수의 기본적인 기능에 대해서 알고 계시겠지만, 처음 보시는 분도 항상 있다고 가정하고 있기 때문에,,,,

 

각설하고, 위의 코드를 줄일 수 있는 방법은 없을까요? 솔직히 foo int, bar int 이 부분이 너무 거추장스럽지 않나요? 둘 다 정수형 타입인데 묶어줄 수 있으면 묶어주는게 최고일텐데요, 네 가능합니다. 아래의 코드를 통해서 한번 동작시켜보세요!

 

func addFoo(foo ,bar int, rea float64) int {
	if (foo > bar){
		return foo + 10;
	} else if (foo < bar) {
		return bar + 5;
	} else {
		return foo + bar;
	}
}

func main() {
	fmt.Println(addFoo(10,20, 3.14))
}

 

foo와 bar는 둘다 정수형 타입입니다. 그렇기 때문에 위처럼 묶어줄 수 있습니다. 하지만 이까지만 설명한다면 그다음에 오는 인자가 정수형 타입이 아닐 경우엔 어떡해요 할까 봐 조용히 하나 넣어놓았습니다...^^

 

고 언어는 파이썬과도 비슷하게 함수의 반환 값이 하나 이상 반환이 가능합니다. 아래 코드를 보고 넘어가도록 하겠습니다.

 

package main

import "fmt"

func swap(x, y string) (string, string) {
	return y, x
}

func main() {
	a, b := swap("foo", "bar")
	fmt.Println(a, b)
}

 

보시게 되면, 두 개의 문자열을 반환합니다. 그렇기 때문에 반환값의 리턴에도 두개의 값이 들어가는 게 맞겠죠? 그리고 함수를 통해서 값을 마치 언패킹 하듯이 받는다고 생각할 수 있으나, 이는 그러한 개념과는 조금 근본적으로 다릅니다. 복수 값을 반환하는 것과 복수값을 여러 변수가 언패킹해서 각자의 데이터를 가져가는 것은 의미론적으로 비슷할 수 있으나 go언어는 그냥 복수값을 반환하는 것입니다.

 

>>> def move():
...     return 1, 2
...
>>> a = move()
>>> a
(1, 2)
>>> foo,bar = move()
>>> foo, bar
(1, 2)
>>> foo
1

 

아시겠죠? 고 언어에서는 아래와 같은 오류를 얻습니다. 

 

package main

import "fmt"

func swap(x, y string) (string, string) {
	return y, x
}

func main() {
	a:= swap("foo", "bar")
	fmt.Println(a)
}


-> 10:3: assignment mismatch: 1 variable but swap returns 2 values

 

그러니까 근본적으로 다르다는 게 파이썬은 복수 값을 리턴해도 하나의 변수가 그걸 모두 받아 패킹해 튜플로 지닐 수 있으나, 고 언어에서는 복수값을 리턴한다면 복수 변수가 그것을 받을 준비를 해야 된다는 말입니다. 혼동하시면 안 됩니다!!

 

Naked Return

고 언어의 반환 값은 함수 내부의 변수로도 정해질 수 있습니다. 조금 아리송하게 들리시겠지만 아리송한 내용이니 아리송하게 들릴 수밖에요. 만약 반환 값이 없는 함수라면 리턴 타입에 정의된 리턴 값을 반환합니다. 하지만 이는 함수의 사이즈가  클 때는 절대 이렇게 사용하시면 안 됩니다. 어디 있는지 찾지도 못하고 컴파일러도 같이 헤매게 될 테니까요.

 

package main

import "fmt"

func addFoo() (foo, bar int) {
	foo = 10 * 2
	bar = 100 * 30
	return
}

func main() {
	fmt.Println(addFoo())
}

 

한번 훑고 지나가세요, 어차피 하다 보면 자연스러워지게 되어있으니까요. 

 

 

어느새 함수와 변수 등 고 언어의 아주 기본적인 내용에 대해서 모두 학습했습니다. 이제 제어 - 반복문에 대해서 학습을 같이 또 해나가야 할 텐데, 조금 어려운 것 같아도 같이 공부해봅시다!!

 

 

글 잘 읽으셨다면 공감 하트 눌러주시면 감사하겠습니다!!!😆😆😆😆

 

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

 

읽어주셔서 감사합니다!!!🥰🥰🥰🥰🥰🥰🥰

 

다음 글 ---->

hazarddev.tistory.com/68

 

[Go#4] Go언어 For, if_(반복문, 제어문) 이해하기!!!

Powerful Concurrency Language Go 저번 시간에 패키지와 함수에 대해서 간략하게 알아보았습니다. 이번 시간에는 반복문과 제어문에 대해서 학습해보도록 하겠습니다. 다른 프로그래밍 언어에 대해서

hazarddev.tistory.com

 

728x90

댓글