Go를 배워보자 2일차 - 컴파일, 조건문, 반복문

0

Go

목록 보기
2/12

컴파일, 조건문과 반복문

1. 컴파일

Go는 컴파일 언어이다. 따라서, 소스 코드를 컴파일하여 cpu가 실행할 수 있는 바이너리 포맷으로 변환해 주어야 한다.

source.go --컴파일--> 바이너리 파일(실행파일) ---> 실행

이에 따라 go를 실행할 수 있는 명령어는 다음과 같다.

  1. go build : 소스 코드를 바이너리로 컴파일한다.
  2. go run : 프로그램을 컴파일한 다음 즉시 실행한다. 컴파일된 실행 파일은 저장하지 않는다.
  3. go fmt : 소스 코드 형식을 go 표준 포맷으로 정렬한다.
  4. go version : 현재 설치된 go의 버전을 보여준다.

vs code에서 자동으로 사용되지 않은 변수나, package를 제외시키는 것은 go 표준 포맷으로 정렬하는 것이다. vscode에서 코드를 작성했을 때 사용하지 않은 패키지가 자동으로 사라지는 것도 go fmt가 작동했기 때문이다.

2. 조건문

go에서의 조건문은 c, c++에서와 마찬가지로 if, if-else, if-else if-else이다.

그런데, 특이한 것은 python처럼 () 을 쳐주지 않아도 된다는 것이다.

package main

import "fmt"

func main() {
	grade := 90
	if 90 <= grade {
		fmt.Println("A") // A
	} else if 60 <= grade && grade < 90 {
		fmt.Println("B")
	} else {
		fmt.Println("C")
	}
}

바로 다음과 같이 if문을 사용하면 된다.
if문 뒤로는 ()을 써주지 않고 조건식을 써주면 되는 것이다.

go에서 입력을 처리하는 함수를 작성할 때 한가지 문제가 있다. 이 때 조건문을 사용하면 아주 좋은 해결방법을 제시할 수 있다.

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	input := reader.ReadString('\n') //  '\n'이 나올 때까지 입력을 받겠다는 의미 , 즉 엔터키를 입력 받기 전까지는 받겠다.
	fmt.Print(input)
}

다음의 코드는 입력을 받는 코드이다. 그런데, 에러가 발생하고 다음의 문구가 나올 것이다.

.\main.go:11:8: assignment mismatch: 1 variable but reader.ReadString returns 2 values

이것이 무슨말이냐고 하면, reader.ReadString() 함수의 리턴값이 두 개인데 하나만 받았다는 것이다.

그렇다면 다음의 코드로 변경할 수 있다.

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	input, _ := reader.ReadString('\n')
	fmt.Print(input)
}

_ 을 사용하여 리턴으로 받는 값을 무시하는 것이다.
실제로 잘 구동한다. 그러나, 문제는 다음이 있다.

func (*bufio.Reader).ReadString(delim byte) (string, error)

다음은 ReadString 함수의 정의이다. 뭐가 뭔지는 모르겠지만 어찌됐든 간에 ReadString의 반환값 둘은 string 과 error인 것은 알게되었다.

두번째 인자가 error 메시지라는 것이다. 그런데 이걸 _ 로 받게되면 에러가 발생시에 정확한 이유를 알 수 없게된다는 단점이 있다.

따라서, error를 받아보도록 하자

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	input, error := reader.ReadString('\n')
	fmt.Print(input)
}

그러나 error를 받아도 사용하지 않으면 go는 오류를 일으킨다. 따라서, error를 출력하도록 하자

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	input, error := reader.ReadString('\n')
	fmt.Print(input)
	fmt.Print(error)
}

문제는 error를 프린트하면 nil이라는 것도 반환한다는 것이다. nil은 무엇일까? nil은 golang에서 error타입의 값이 아무런 error가 없다는 것을 보고하기 위해 지정된 값이다.

따라서 nil이 나왔다는 것은 에러가 없다는 것인데 nil까지 print되므로 마치 error를 보고한 것처럼 복잡해졌다. 따라서 이를 조건문 처리하여 nil일 때는 error를 출력하지 않도록 하자

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	input, error := reader.ReadString('\n')
	fmt.Print(input)
	if error != nil {
		fmt.Print(error)
	}
}

이렇게 if조건문을 이용하면 원하는 조건에 따라 로직을 변경할 수 있게 된다.

  • 이름 섀도잉
    위의 코드에서 error로 error타입의 반환값을 받았다. 그런데, 생각해보면 이는 int타입의 반환값을 int라는 변수로 받은 것과 마찬가지이다.

golang은 이처럼 기존에 있던 것들이라도 , 충돌이 났다는 에러를 발생하는 것이 아니라, 재정의를 하게된다.

따라서, 내가 error라는 변수를 만들었기 때문에 이제부터는 error라는 타입은 사라지게 되는 것이다.

package main

import "fmt"

func main() {
	var int int = 10
	var count int = 20 // .\main.go:7:6: int is not a type
	fmt.Print(count)
}

다음의 코드를 보면 int라는 변수를 만들었지만, 기존 타입인 int와 겹친다는 컴파일 에러조차 발생하지 않는다. 그러나, 이는 굉장히 위험한 것인게 golang은 int라는 변수를 만들게됨으로서 int라는 기존 타입은 삭제하게 된다.

따라서 우리는 count의 자료형을 int로 적었음에도 불구하고 int is not a type이라는 에러가 발생하게 되는 것이다.

이름이 "네임 섀도잉" 이다.
변수가 기존의 함수, 타입, 패키지, 변수의 존재를 가리기 때문이다.

따라서, 우리는 error변수가 아닌 err변수로 받는 것이 맞다.

3. 반복문

golang의 기가막힌 문법 중 하나는 반복문이다. if문처럼 ()가 없다. 또, golang은 for문 밖에 반복문이 없다. 즉, while문이 따로 없다.

for x:= 4; x <= 6; x++ {
    fmt.Print("x" , x)
}

4부터 x를 시작하여 6까지 순회하라는 것이다. 기본적인 c/c++, java함수와 같지만, () 가 없다.

package main

import "fmt"

func main() {
	for i := 0; i < 10; i++ {
		fmt.Print(i) // 0123456789
	}
}

golang에서는 while문이 따로없다. 그래서 for문으로 모두 처리해야 한다.

  • while 문처럼 사용하기
package main

import "fmt"

func main() {
	i := 0
	for i < 10 {
		fmt.Print(i) // 0123456789
		i++
	}

}
  • for ... in 처럼 사용하기

또한, for문에 range를 주어서 마치 for ... in 이나, python의 for문 처럼 사용이 가능하다.

package main

import "fmt"

func main() {
	strings := []string{"hello", "world"}
	for i, s := range strings {
		fmt.Println(i, s)
	}
	// 0 hello
	// 1 world
}

strings는 string 배열이다. 배열의 선언은 추후에 알아보도록하고, "hello"가 0번째 인덱스에 "world"가 1번째 인덱스에 있음을 알 수 있다.

여기서 range 키워드를 사용하면 배열의 element를 하나씩 가져오는데 첫번째 값이 index이고 두 번째가 value이다.

따라서 i는 index가 되고, s는 value가 되어 string 값이 나오는 것이다.

  • while(true) 무한 루프 사용
    while(true)를 사용하고 break문을 사용하고 싶다면, for문에 굳이 true라고 적어줄 필요가 없다.
package main

import "fmt"

func main() {
	i := 0
	for {
		if i == 5 {
			break
		}
		fmt.Print(i) // 1234
		i++
	}
}

물론 for에 true를 써주어도 되지만 안써주어도 true로 판별된다.

0개의 댓글