Go 에서는 반복문이 for문 하나밖에 없다. 사실 다른언어에서도 while문을 거의 없었고 대부분 for문으로 해결을했으니 굳이 상관은 없을것 같다.
다른 언어와 마찬가지로 go의 for문도 for (초기값); (조건); (증감식) {..}
순서로 쓴다.
하지만 초기값; 조건; 증감식
을 쓸때 () 는 생략한다 안그러면 에러가 난다.
n := 0
for n<100 {
n++
}
조건식만 쓰고 나머지를 생략했다. 그저 n
이 100 미만 인지만 판단을하는 for문이고 내부에서 n을 직접 증가 시키고 있다.
for {
println('forever')
}
javascript의 for of 문 과 같다. 순회가 가능한 자료형의 요소들을 하나씩 꺼내서 사용한다.
array := []int{1,2,3} //아직 배우지 않았지만 go에서의 배열 형태이다.
for i,v := range array { //배열에서 index,value 순서로 꺼내서 사용한다.
println(i,v)
}
//index를 생략하려면 이런방식으로 쓴다.
for _,v := range array{
println(v)
}
다른 언어들과 마찬가지로 continue
문으로 루프의 한 단계를 건너뛸수있고 break문으로 반복문을 빠져나갈수있다.
func (함수명) ({파라미터} {파라미터 타입}) (리턴 타입) {...}
으로 함수를 선언한다.
func sum(a,b int) int {
return a+b
}
func main() {
println(sum(1,2))
}
별도의 리턴값이 없다면 리턴타입 생략이 가능하다
func printText(text string) {
println(text)
}
go에서 파리미터는 Pass by value
와 Pass by reference
두가지 방식으로 전달할수있다.
복사
하여 함수안에서 사용한다.
func changeText(str string) {
str = "changed"
}
func main(){
str := "text"
changeText(str)
}
즉 위와같은 코드를 실행했을때 main 에서 선언된 str의 값은 changeText 가 실행되어도 바뀌지 않는다.&
를 붙여 메모리 주소 자체를 전달한다.*string *int
와 같이 파라미터가 포인터임을 표기하고 해당 함수안에서 사용하는 변수도 값이 아닌
메모리 주소 자체를 가지게 된다. 이 함수안에서 사용하는 모든 변수는 앞에 *
를 붙여야한다.
(근데 솔직히 아직까진 뭔소린지 모르겠다 나중에 다시 정리해야할듯)
func changeText(str *string) { //파라미터가 포인터라는걸 표시
*str = "changed" //pass by reference 함수안에서는 반드시 * 을 붙여서 사용
}
func main(){
str := "text"
changeText(&str) //이 함수를 호출하고 나면 main의 str 값이 바뀜
}
함수의 파라미터 수가 고정되지 않은 함수로 파라미터 변수 앞에 ...
을 붙여 사용할수 있다.
func someFunction (str ...string) {
//이 함수의 str 파라미터는 배열 형태로 전달된다
for _,text := range str {
println(text)
}
}
go에서 함수는 리턴값이 없을수도, 하나일수도, 여러개일수도 있다.
또한 함수의 리턴값이 여러개일때
리턴값을 미리 지정하여 코드의 가독성을 높이는 방법도 있다. 이를 Named Return Parameter 라고 하더라.
여러개의 리턴값이 있는 함수
func plusMinus(a,b int) (int,int) {
plus := a+b
minus := a-b
return plus,minus
}
함수의 리턴값이 여러개면 리턴 타입을 괄호로 묶어 선언하고 만약 리턴 타입이 다를경우 (int,string) 과 같은 형태로 적는다.
Named Return Parameter 를 적용한 함수 위의 plusMinus 함수를 좀더 간결하게 적을수있다.
func plusMinus(a,b int) (plus int,minus int) {
plus = a+b //함수 안에서 별로도 변수를 선언하지 않고 리턴 타입을 정의할때 바로 plus,minus라는 이름을 정했다.
minus = a-b
return //위에서 정의한 (plus int, minus int)가 바로 반환된다.
}
javascript 처럼 익명함수를 사용할수 있다.
익명함수는 변수자체에 할당되거나 다른함수의 파라미터 자체로 넘겨줄수도있다.
func main() {
sum := func(a,b int) int { //main 함수 안에서 sum 이라는 변수 자체에 함수를 할당하고있다.
return a+b
}
println(sum(1,2)) //변수명 자체가 함수 호출이된다
}
일급함수란 함수 자체를 다른 변수에 할당하거나 다른 함수의 파라미터로 전달할수있는 함수를 뜻하며 또한 리턴값으로 함수를 넘길수도 있다.
일급함수를 가진 언어
란 이런 기능을 지원하는 언어를 뜻한다. 대표적으로 javaScript 와 python 등이 있고 go 또한 일급 함수를 가진 언어이다.
함수의 파라미터에 함수 전달하기
func main() {
plus := func(a, b int) int {
return a + b
}
minus := func(a, b int) int {
return a - b
}
calc := func(cb func(int, int) int, a, b int) int {
res := cb(a, b)
return res
}
println(calc(plus, 1, 2))
println(calc(minus, 1, 2))
}
위의 예제는 더하기, 빼기 함수를 calc
라는 함수의 파라미터로 넘기면서 calc 내부에서 호출하고있다.
선언이 다소 복잡하지만 calc의 선언 부분을 보면 파라미터에 함수명 func(int,int) int
와 같이 int형 두개를 받으며 리턴값이 int 하나인 함수 라는
함수의 원형
을 정의했다.
이 함수의 원형이 다른곳에서도 자주 쓰인다면 type
키워드를 사용해 직접 함수의 원형을 타입으로써 정의해 두고 사용할수도 있다.
함수의 원형을 타입으로 정의한 예제
type calculator func (int,int) int
func calc (cb calculator,a,b int) int {
res := cb(a,b)
return res
}
javascript를 배웠을때도 Closure
라는 개념을 완전히 익히기 까지 꽤나 애를먹었던 기억이 있다. (사실 까먹어서 방금 다시 읽어봄)
go에서도 함수가 클로저의 역할을 할수도 있는데 먼저 간단하게 클로저의 개념을 설명하자면 함수 내부에 또다른 함수를 작성하는 경우
다.
위에서 언급했듯이 일급함수를 가진 언어는 리턴값으로 함수를 반환할수있고 아래의 예제와 같이 함수가 자신의 내부에 선언된 함수를 리턴하는 경우다.
func outterFunc() func() {
msg := "this is outterFunc's variable" //outter 라는 함수안에 변수를 선언하였다.
innerFunc := func() { //outter 함수안에 inner 라는 함수를 선언하고 outter의 변수를 사용하고있다.
println(msg)
}
return innerFunc //inner 함수를 반환하고있다.
}
func main() {
mainInner := outterFunc()
/*
main에서 outter를 호출하면 내부의 inner 함수를 받게된다. 이제 이 mainInner 라는 함수는
outter에서 반환한 inner 함수를 가지고있다
*/
mainInner() //outter에서 받은 inner 함수를 호출한다. "this is outterFunc's variable" 이 출력된다.
}
이 예제에서 주목할점은 inner 함수가 outter 함수의 변수에 접근이 가능하다는 점
이다.
outter가 반환한 inner 함수를 main에서 가지고 있다가 필요할때 언제든지 호출하여 outter 함수가 가진 msg라는 값에 접근할수있다.
자세한 설명을 하자면 글이 너무 길어지니(사실 귀찮아서) 클로저
에 대해 자세히 읽어보고 싶다면 이 글을 참조하자. 본인이 클로저의 개념을 이해할때까지 읽었던 글인데 내용 정리가 잘 되어있다.