Powerful Concurrency Language Go
저희 저번 시간에는 고 언어의 변수의 타입과 타입 캐스팅에 대해서 알아보았습니다. 물론 만약 못 보신 분이 계시다면 아래 링크를 통해서 보고 오시는 것을 추천드립니다!! 물론 알고 계신다면 보고 올 필요가 전혀 없겠죠.
이번 시간에는 고 언어의 패키지와 간단한 함수 기능에 대해서 학습해볼 예정입니다.
Package
모든 고 언어로 작성된 프로그램들은 패키지로 패킹됩니다. 그러니까 만약 아래의 코드가 있다면,
func main(){
/*** code section ***/
}
main패키지안에서 프로그램 시작 영역이 지정되기 때문에 main패키지라 불러도 무방합니다. 블로그 글에 자주 나오는 fmt는 고 언어의 표준 라이브러리 패키지입니다. 이 또한 패키지라고 지칭하면 됩니다. 그 외에도 내장 패키지들이 많지만 자주 사용해볼 법한 패키지는 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())
}
한번 훑고 지나가세요, 어차피 하다 보면 자연스러워지게 되어있으니까요.
어느새 함수와 변수 등 고 언어의 아주 기본적인 내용에 대해서 모두 학습했습니다. 이제 제어 - 반복문에 대해서 학습을 같이 또 해나가야 할 텐데, 조금 어려운 것 같아도 같이 공부해봅시다!!
글 잘 읽으셨다면 공감 하트 눌러주시면 감사하겠습니다!!!😆😆😆😆
댓글로 문의, 피드백, 질문 모두 환영합니다!!!
읽어주셔서 감사합니다!!!🥰🥰🥰🥰🥰🥰🥰
다음 글 ---->
'Go' 카테고리의 다른 글
[Go#6] Go언어 pointer, struct 문법!!! (0) | 2021.01.14 |
---|---|
[Go#5] Go언어 Switch, Defer 문법!!! (0) | 2021.01.12 |
[Go#4] Go언어 For, if_(반복문, 제어문) 이해하기!!! (0) | 2021.01.07 |
[Go#2] Go언어 변수_ 상수, 타입, 타입 캐스팅!!! (0) | 2021.01.03 |
[Go#1] Go언어 설치 및 기본 사용방법!!! (0) | 2021.01.02 |
댓글