Go언어가 타 언어와 다른점은Class문법이 없다는 것입니다.
Go언어 함수의 구성요소는func키워드, 함수 이름, 입력, 출력 정도가 있습니다.
package main
import (
"fmt"
"log"
)
func sayHello(message string) (string,error) {
return message, nil
}
func main() {
helloGo, err := sayHello("Hello, Go!")
if err == nil {
log.Fatal(err)
}
// -> Hello, Go!
fmt.Println(helloGo)
}
처음보는
nil이란 키워드는 포인터, 인터페이스, 맵, 슬라이스, 채널 함수의zero value로 주로error가 없을때 반환합니다.
Func키워드를 사용하여sayHello라는 함수를 정의하고, 인자값으로는string타입의message를 입력받고 출력부분은(string,error)이 부분을 통해 출력값은string과error타입으로 반환하도록 정의하였습니다.
return message, nil이 부분이 타 언어와 조금 다른데Go언어에서는return값으로 여러개의 값을 돌려줄 수 있습니다.
return키워드는 함수에서 값을 반환할 때 사용하며,return을 사용하면 이후의 코드는 실행되지 않습니다.
package main
import (
"errors"
"fmt"
"log"
)
func sayHello() (string,error) {
if err := errors.New("Err"); err != nil {
return "",err
}
return "Hello, Go!", nil
}
func main() {
helloGo, err := sayHello()
if err != nil {
/**
-> Error
*/
log.Fatal(err)
}
fmt.Println(helloGo)
}
리턴을 명시할 때 이름도 같이 명시해주는것으로 해당 리턴값이 의미하는것을 다른 개발자에게 알려줄 수 있는 도구로 사용되기도 합니다.
package main
import "fmt"
func sayHello() (helloGo string) {
helloGo = "Hello, Go!"
return
}
func main() {
helloGo := sayHello()
fmt.Println(helloGo)
}
또는 아래와 같은 방식으로도 코드를 작성할 수 있습니다.
func sayHello() (helloGo string) {
return "Hello, Go!"
}
함수는 하나의 스코프로 동작할 수 있으며 함수 자신보다 상위의 스코프에서 선언한 변수에 대해서는 접근 할 수 있지만, 함수 내부에서 선언한 변수에 대해서 상위 스코프에 접근할 수 없습니다.
따라서 아래의 코드에서 패키지 스코프에 선언한
message변수는 접근이 가능하지만, 함수 스코프에서 선언한helloGo변수에 대해서는 접근할 수 없습니다.
package main
import "fmt"
var message string = "Hello, Go!"
func sayHello() {
helloGo := message
}
func main() {
sayHello()
/**
-> Error
fmt.Println(helloGo)
*/
}
Go언어에서 함수는 중요하게 여겨지고 있으므로, 익명함수 또한 존재합니다.함수를 파라매터로 넘길 수 있으며, 값으로 취극할 수 있습니다. 그 말은 함수를 값으로써 여길 수 있다면 일급 함수이며 함수를 리턴하거나 함수를 파라매터로 받거나 리턴한다면 그 함수는 고차 함수라고 할 수 있습니다.
package main
import "fmt"
func each(arr []string, iterator func(string)) {
for _,v := range arr {
iterator(v)
}
}
func main() {
p := func(v string) {
fmt.Println(v)
}
/**
each([]string{"Hello, Go!", "Who are You"}, func(v string)) {
fmt.Println(v)
}
*/
each([]string{"Hello, Go", "Who are You"},p)
}
Go언어의 함수는 일급 함수(First-Class)입니다. 일급 함수는 함수형 프로그래밍에서 쓰이는 개념으로써, 함수를 다른 함수의 파라매터로 넘기거나 변수에 담고, 리턴으로 사용하는 등, 함수 자체를 값 처리할 수 있는것을 의미합니다.
defer키워드는Go에서 지원하는 특이한 키워드 중 하나입니다.
defer를 사용하면 함수가 종료될 때 호출됩니다 ( 지연 실행 ). 런타임 중에 에러가 발생한다고 해도defer키워드를 사용한 함수는 호출이 보장됩니다.
defer를 여러개 사용하는것도 가능한데, 이는 스택( 후입 선출 )으로 쌓이기 때문에 가장 나중에 설정된defer부터 실행됩니다.
package main
import "fmt"
func main() {
defer func() {
fmt.Println("함수가 종료될 때 실행합니다.")
}()
defer func() {
fmt.Println("defer는 후입선출 방식으로 늦게 스택에 쌓인 defer가 먼저 실행됩니다.")
}()
fmt.Println("메인 스코프가 종료되었습니다.")
}
go키워드는 동시성을 쓸 때 사용합니다.
Go언어의 동시성은 기본적으로OS쓰레드를 한 층 더 추상화한 코루틴(co-routine)이며 비동기적 프로그래밍을 할 수 있습니다.
Go언어에서는 이를 고루틴(go-routine)이라고 합니다. 고루틴은 멀티 쓰레딩을 활용할 때 유용한데, 쓰레드에 자원을 배분하거나 쓰레드 자체에 대해 간섭하는 것을 고 런타임이 알아서 해줍니다.
package main
import (
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
func main() {
wg.Add(1)
go func() {
defer wg.Done()
for i := 0; i < 10; i++ {
fmt.Println(i)
time.Sleep(time.Second)
}
}()
wg.Add(1)
go func() {
defer wg.Done()
for _, byte := range "Hello, Go!" {
fmt.Printf("%c\n",byte)
time.Sleep(time.Second)
}
}()
wg.Wait()
fmt.Println("GoodBye")
}
아래의 2개의 고루틴은 숫자와 문자를 번갈아서, 혹은 임의의 순서를 가지고 출력될 것입니다.
여기서
sync.WaitGroup을 사용한 것을 확인할 수 있는데main()함수 또한 고루틴이며 만약 다른 고루틴보다main()고루틴이 먼저 끝날경우 프로그램 자체가 종료되기 때문에 이를 사용한 것이라고 보면 됩니다.고루틴과 동시성에 대한 내용은 별도로 주제를 나눠 이야기 해야하기 때문에 함수에서는 일단 동시성을 위해
go키워드를 사용할 수 있다는것 만 알아두고 넘어가도록 합시다.
Go언어의 함수가 다른 언어에 비해 지원하지 않는 것들을 알아둘 필요가 있습니다.
Go에서 함수 파트에 대해 지원하지 않는 것은 다음과 같습니다.
default value)선택적 파라매터는 파라매터가 있을 수도 있고 없을 수도 있는 것입니다.
기본 값은 함수 호출시 해당 파라매터에 대한 값을 넘기지 않았을 경우 적용할 값입니다.
Go 언어 공부 GoGo~~! 엌ㅋㅋㅋㅋㅋㅋㅋ