chapter 5
에서는 Go 언어를 사용하면서 종종 사용하게 될 표준입출력(Standard Input/Output)에 대해서 설명한다.
크게 아래의 주제로 설명한다.
1. 표준 입출력과 fmt
패키지
2. 표준 출력
3. 표준 입력
4. 표준 입력 스트림의 작동 원리
fmt
패키지?프로그램과 사용자가 상호작용을 위해서는 서로의 정보를 주고 받을 필요가 있다. 이때 크게 입력과 출력 형태로 상호작용을 수행하게 되는데,
예를 들어 콘솔 창에 원하는 문자열을 입력한다던지, 입력받은 문자열을 처리해서 화면에 노출시켜준다던지 하는 것들을 Standard Input/Output 즉, 표준 입출력이라고 한다.
단순히, 키보드를 통해 문자를 입력하는 것만이 표준입출력이 아니라, 네트워크를 통해, 혹은 파일 시스템을 통해 프로그램으로 데이터를 가져와 적재하는 것 등, 여러가지 데이터를 통한 상호작용은 표준입출력을 통해 수행된다고 보면된다.
하지만, 프로그래머가 일일히, 모든 입력과 출력을 구현하고 제어해야한다면 매우 생산성이 낮아질 것이고, 개발하고자 하는 프로그램의 복잡도는 높아질 것이다. 이를 위해 프로그래머는 OS에서 제공하는 Standard Input/Output Stream(표준입출력 스트림)
을 통해
현재 자신이 개발하고 있는 프로그램에 간편하게 표준입출력 기능을 이식할 수 있다.
대부분의 프로그래밍 언어는 표준입출력을 제어하기 위한 빌트인 모듈, 패키지 등이 존재한다. Go언어에서는 fmt
패키지를 통해서 표준입출력 기능을 사용할 수 있는데,
fmt
패키지 안에서는 표준입출력 뿐만 아니라, Go언어에서 사용되는 다양한 기능을 가진 함수를 제공하고 있다. 프로젝트에서 fmt
패키지를 사용하고 싶다면 아래와 같이 import
를 해야한다.
import "fmt"
fmt
패키지에서는 3가지 표준 출력용 함수를 제공한다
1. fmt.Print()
2. fmt.Println()
3. fmt.Printf()
fmt.Print()
함수는 인자로 주어진 값들을 콘솔에 출력하는 함수다. 인자는 vararg
로 여러 값들이 전달될 수 있다.fmt.Println()
함수는 fmt.Print()
함수와 동작이 똑같지만, 마지막에 개행(\n
)을 추가하여 출력한다. 즉, 이 함수를 사용하면 자동적으로 줄바꿈이 되는 것을 확인할 수 있다.fmt.Printf()
메서든는 [%d
, %f
, %g
, %c
, %s
, 등]과 같이 여러 서식문자에 맞게 문자열을 출력해준다(c언어에서 printf라고 생각하면 된다.)일반 built-in 함수인 print함수는 Standard Error를 반환하는 함수로 fmt.Print 함수와는 목적이 다른 함수다.
fmt
패키지에서는 3가지 표준 입력용 함수를 제공한다. 아래의 함수들의 반환 값으로는 성공적으로 입력받은 인자의 개수와, 입력 실패시 반환되는 에러메세지를 반환한다. 만약 에러메세지나 nil
이라면 성공적으로 모든 입력을 동작했다고 생각하면 된다.
1. fmt.Scan()
2. fmt.Scanln()
3. fmt.Scanf()
fmt.Scan()
표준 입력에서 값을 입력받는데, 함수는 vararg
로 여러 값들이 인자로 전달될 수 있다. 인자의 형식으로는 아래와 같이 입력 값들을 저장할 변수의 주소를 입력한다.var a int
var b int
n, err := fmt.Scan(&a, &b)
정수 변수 a
, b
에는 각 입력된 문자가 정수로 변환되어 저장이된다. n
에는 성공적으로 입력받은 개수와 err
에는 입력 실패 시의 에러메세지가 저장된다.
fmt.Scanln()
함수는 한 줄을 입력받아 각 인자로 들어온 변수에 주소에 각 입력 값들을 저장하는 함수로 마지막에 enter
키로 명시적으로 종료해줘야한다.
var a int
var b int
n, err := fmt.Scanln(&a, &b)
fmt.Scanf()
메서든는 [%d
, %f
, %g
, %c
, %s
, 등]과 같이 여러 서식문자에 맞게 입력을 받아 변수에 저장한다.var a int
var b int
n, err := fmt.Scanf("%d %d\n", &a, &b)
Scan()
이나 Scanln()
함수를 사용하는 것을 추천한다.사용자가 표준 입력 장치를 통해 데이터를 입력하면, 이 데이터는 컴퓨터 내부 어디에 저장이 될까라는 질문의 답은 바로 stndard input stream(표준입력스트림)
이라는 메모리 공간에 임시 저장된다. 표준 입력 함수들인 fmt.Scan()
,fmt.Scanln()
,fmt.Scanf()
들은 이러한 표준입력스트림
버퍼에서 값을 하나씩 읽어서 처리하는 방식이다. 버퍼는 FIFO
구조를 가지고 있으며, 표준 입력 함수는 버퍼에서 하나씩 읽어서, 원하는 타입일 경우에는 변수에 해당 값을 저장하고, 아니라면 Error
를 반환한다. 이 때, Error
를 반환한 채로 함수가 수행을 종료했기 때문에, 버퍼에는 아직 처리하지 못한 값들이 남아있고, 버퍼를 비워주지 않고, 다시 한번 더 표준 입력 함수가 수행된다면, 버퍼에 남아있는 값들을 읽기 때문에, 의도치 않은 오류가 발생할 수 있다. 이러한 상황을 방지하기 위해서는 아래와 같이 표준입출력스트림
버퍼를 비워줘야한다.
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
stdin := bufio.NewReader(os.Stdin) //표준입력스트림을 읽는 객체
var a int
var b int
n, err := fmt.Scanln(&a, &b)
if err != nil {
fmt.Println(err)
readString, err := stdin.ReadString('\n')//` \n가 나올때까지 표준입력스트림을 읽는다.
} else {
fmt.Println(n, a, b)
}
n, err = fmt.Scanln(&a, &b)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(n, a, b)
}
}
좋은 글 감사합니다.