Go 언어 fmt.Printf
완벽 가이드: 이제 두렵지않은 printf
사용법 알아볼까요?
Go 언어를 사용하다 보면 fmt
패키지의 printf
계열 함수들을 자주 만나게 한데요.
이번에는 Fprintf
, Printf
, Sprintf
함수들의 포맷 지정 방법에 대해 자세히 알아보겠습니다.
모든 타입에 사용할 수 있는 verb
%v
값을 기본 형식으로 출력합니다.
기본 타입의 경우
타입 | verb |
---|---|
논리값 (bool ) |
%t |
부호 있는 정수 (int , int8 등) |
%d |
부호 없는 정수 (uint , uint8 등) |
%d |
부동소수점수 (float64 등) |
%g |
복소수 (complex128 등) |
%g |
문자열 (string ) |
%s |
채널 (chan ) |
%p |
포인터 (pointer ) |
%p |
package main
import (
"fmt"
)
func main() {
fmt.Printf("%v\n", true)
fmt.Printf("%v\n", 42)
fmt.Printf("%v\n", uint(42))
fmt.Printf("%v\n", 12.345)
fmt.Printf("%v\n", 1-2i)
fmt.Printf("%v\n", "초밥🍣맥주🍺")
fmt.Printf("%v\n", make(chan bool))
fmt.Printf("%v\n", new(int))
}
true
42
42
12.345
(1-2i)
초밥🍣맥주🍺
0x434080
0x416028
합성(composite) 타입의 경우
각 요소에 대해 재귀적으로 %v
포맷을 적용한 결과를 출력합니다.
타입 | 포맷 |
---|---|
구조체 (struct ) |
{필드1 필드2 ...} |
구조체 포인터 | &{필드1 필드2 ...} |
배열・슬라이스 (array , slice ) |
[요소1 요소2 ...] |
배열・슬라이스 포인터 | &[요소1 요소2 ...] |
맵 (map ) |
map[키1:값1 키2:값2 ...] |
맵 포인터 | &map[키1:값1 키2:값2 ...] |
package main
import (
"fmt"
"net/http"
)
func main() {
fmt.Printf("%v\n", http.Client{})
fmt.Printf("%v\n", &http.Client{})
fmt.Printf("%v\n", [...]int{1, 2, 3})
fmt.Printf("%v\n", &[...]int{1, 2, 3})
fmt.Printf("%v\n", []int{1, 2, 3})
fmt.Printf("%v\n", &[]int{1, 2, 3})
fmt.Printf("%v\n", map[string]int{"초밥": 1000, "맥주": 500})
fmt.Printf("%v\n", &map[string]int{"초밥": 1000, "맥주": 500})
}
{<nil> <nil> <nil> 0s}
&{<nil> <nil> <nil> 0s}
[1 2 3]
&[1 2 3]
[1 2 3]
&[1 2 3]
map[맥주:500 초밥:1000]
&map[맥주:500 초밥:1000]
%+v
%v
와 동일하지만, 구조체의 경우 필드 이름을 함께 출력합니다.
package main
import (
"fmt"
"net/http"
)
func main() {
fmt.Printf("%v\n", http.Client{})
fmt.Printf("%+v\n", http.Client{})
}
{<nil> <nil> <nil> 0s}
{Transport:<nil> CheckRedirect:<nil> Jar:<nil> Timeout:0s}
%#v
값을 Go 언어의 문법 형태로 출력합니다.
package main
import (
"fmt"
"net/http"
)
func main() {
fmt.Printf("%#v\n", true)
fmt.Printf("%#v\n", 42)
fmt.Printf("%#v\n", uint(42))
fmt.Printf("%#v\n", 12.345)
fmt.Printf("%#v\n", 1-2i)
fmt.Printf("%#v\n", "초밥🍣맥주🍺")
fmt.Printf("%#v\n", make(chan bool))
fmt.Printf("%#v\n", new(int))
fmt.Printf("\n")
fmt.Printf("%#v\n", http.Client{})
fmt.Printf("%#v\n", &http.Client{})
fmt.Printf("%#v\n", [...]int{1, 2, 3})
fmt.Printf("%#v\n", &[...]int{1, 2, 3})
fmt.Printf("%#v\n", []int{1, 2, 3})
fmt.Printf("%#v\n", &[]int{1, 2, 3})
fmt.Printf("%#v\n", map[string]int{"초밥": 1000, "맥주": 500})
fmt.Printf("%#v\n", &map[string]int{"초밥": 1000, "맥주": 500})
}
true
42
0x2a
12.345
(1-2i)
"초밥🍣맥주🍺"
(chan bool)(0x834100)
(*int)(0x816260)
http.Client{Transport:http.RoundTripper(nil), CheckRedirect:(func(*http.Request, []*http.Request) error)(nil), Jar:http.CookieJar(nil), Timeout:0}
&http.Client{Transport:http.RoundTripper(nil), CheckRedirect:(func(*http.Request, []*http.Request) error)(nil), Jar:http.CookieJar(nil), Timeout:0}
[3]int{1, 2, 3}
&[3]int{1, 2, 3}
[]int{1, 2, 3}
&[]int{1, 2, 3}
map[string]int{"맥주":500, "초밥":1000}
&map[string]int{"맥주":500, "초밥":1000}
%T
값의 타입을 Go 언어의 문법 형태로 출력합니다.
package main
import (
"fmt"
"net/http"
)
func main() {
fmt.Printf("%T\n", true)
fmt.Printf("%T\n", 42)
fmt.Printf("%T\n", uint(42))
fmt.Printf("%T\n", 12.345)
fmt.Printf("%T\n", 1-2i)
fmt.Printf("%T\n", "초밥🍣맥주🍺")
fmt.Printf("%T\n", make(chan bool))
fmt.Printf("%T\n", new(int))
fmt.Printf("\n")
fmt.Printf("%T\n", http.Client{})
fmt.Printf("%T\n", &http.Client{})
fmt.Printf("%T\n", [...]int{1, 2, 3})
fmt.Printf("%T\n", &[...]int{1, 2, 3})
fmt.Printf("%T\n", []int{1, 2, 3})
fmt.Printf("%T\n", &[]int{1, 2, 3})
fmt.Printf("%T\n", map[string]int{"초밥": 1000, "맥주": 500})
fmt.Printf("%T\n", &map[string]int{"초밥": 1000, "맥주": 500})
}
bool
int
uint
float64
complex128
string
chan bool
*int
http.Client
*http.Client
[3]int
*[3]int
[]int
*[]int
map[string]int
*map[string]int
%%
%
자체를 출력할 때 사용합니다.
논리값에 사용할 수 있는 verb
%t
true
또는 false
를 출력합니다.
package main
import (
"fmt"
)
func main() {
fmt.Printf("%t\n", true)
fmt.Printf("%t\n", false)
}
true
false
정수에 사용할 수 있는 verb
%d
10진수로 표현합니다.
%b
2진수로 표현합니다.
%o
8진수로 표현합니다.
%x
16진수로 표현합니다 (a-f 소문자).
%X
16진수로 표현합니다 (A-F 대문자).
%c
유니코드 코드 포인트에 해당하는 문자로 표현합니다.
%q
해당 문자를 싱글 쿼트 '
로 감싼 문자로 표현합니다.
package main
import (
"fmt"
)
func main() {
answer := 42
fmt.Printf("%b\n", answer)
fmt.Printf("%c\n", answer)
fmt.Printf("%d\n", answer)
fmt.Printf("%o\n", answer)
fmt.Printf("%q\n", answer)
fmt.Printf("%x\n", answer)
fmt.Printf("%X\n", answer)
fmt.Printf("%U\n", answer)
}
101010
*
42
52
'*'
2a
2A
U+002A
부동소수점수・복소수에 사용할 수 있는 verb
%b
소수점 없는 지수 표기 (지수는 2의 거듭제곱)
%e
지수 표기
%E
%e
와 동일하지만 e
가 E
로 표기됨
%f
, %F
지수 표기 없이 출력
%g
지수가 크면 %e
, 아니면 %f
형태로 출력
%G
지수가 크면 %E
, 아니면 %F
형태로 출력
package main
import (
"fmt"
)
func main() {
f := 12.345
fmt.Printf("%b\n", f)
fmt.Printf("%e\n", f)
fmt.Printf("%E\n", f)
fmt.Printf("%f\n", f)
fmt.Printf("%F\n", f)
fmt.Printf("%g\n", f)
fmt.Printf("%G\n", f)
fmt.Printf("%g\n", 12345678.9)
fmt.Printf("%G\n", 12345678.9)
}
6949617174986097p-49
1.234500e+01
1.234500E+01
12.345000
12.345000
12.345
12.345
1.23456789e+07
1.23456789E+07
문자열 ([]byte
도 동일)에 사용할 수 있는 verb
%s
그대로 출력합니다.
%q
Go 언어의 문법으로 이스케이프한 문자열을 출력합니다.
%x
한 바이트당 두 자리의 16진수로 출력합니다 (a-f 소문자).
%X
%x
와 동일하지만 A-F 대문자로 출력합니다.
package main
import (
"fmt"
)
func main() {
s := "초밥🍣맥주🍺"
fmt.Printf("%s\n", s)
fmt.Printf("%q\n", s)
fmt.Printf("%x\n", s)
fmt.Printf("%X\n", s)
}
초밥🍣맥주🍺
"초밥🍣맥주🍺"
xec94a0xebb094f09f8da3eba7b5ec9dbceb8dba
EC9490EBB094F09F8DA3EBA7B5EC9DBCEB8DBA
width와 precision
verb 바로 앞에 정수를 지정하여 width
를 설정할 수 있습니다.
width
는 출력할 문자열의 최소 길이(rune 단위)를 의미합니다. 지정하지 않으면 필요한 만큼의 길이가 됩니다.
precision
은 width
바로 뒤에 .
을 쓰고 정수를 지정하여 설정할 수 있습니다.
.
만 쓰고 숫자를 지정하지 않으면 precision
은 0이 됩니다.
width
와 precision
에 *
를 사용하면 다음 인자의 값으로 지정할 수 있습니다.
이때 그 인자는 정수여야 합니다.
문자열의 경우
precision
은 출력할 문자열의 최대 길이(rune 단위)입니다. 문자열이 너무 길면 잘립니다.
%x
또는 %X
의 경우 바이트 단위로 처리됩니다.
부동소수점수의 경우
width
: 출력될 문자열의 최소 길이precision
:%e
,%f
의 경우 소수점 이하 자릿수%g
,%G
의 경우 유효 자릿수의 최대값
- 기본값:
%e
,%f
,%#g
: 6%g
: 필요한 만큼의 자릿수
복소수의 경우 width
와 precision
이 실수부와 허수부 각각에 적용되며, 결과는 ()
로 감싸집니다.
package main
import (
"fmt"
)
func main() {
f := 12.345
fmt.Printf("%f\n", f)
fmt.Printf("%12f\n", f)
fmt.Printf("%12.2f\n", f)
fmt.Printf("%.2f\n", f)
fmt.Printf("%12.f\n", f)
fmt.Printf("%e\n", f)
fmt.Printf("%#g\n", f)
fmt.Printf("%g\n", f)
fmt.Printf("%f", 1-2i)
}
12.345000
12.345000
12.35
12.35
12
1.234500e+01
12.3450
12.345
(1.000000-2.000000i)
플래그 (flags)
width
와 precision
외에도 verb 앞에 플래그를 사용하여 포맷을 변경할 수 있습니다.
+
- 숫자: 양수에도 부호(
+
)를 표시합니다. %q
: ASCII 문자만 출력합니다.
package main
import (
"fmt"
)
func main() {
fmt.Printf("%d\n", 42)
fmt.Printf("%+d\n", 42)
fmt.Printf("%q\n", 945)
fmt.Printf("%+q\n", 945)
fmt.Printf("%q\n", "초밥🍣맥주🍺")
fmt.Printf("%+q\n", "초밥🍣맥주🍺")
}
42
+42
'α'
'\u03b1'
"초밥🍣맥주🍺"
"\ucd08\ubc15\U0001f363\ub9db\uc8fc\U0001f37a"
-
왼쪽 정렬을 합니다.
package main
import (
"fmt"
)
func main() {
fmt.Printf("%5d\n", 42)
fmt.Printf("%-5d\n", 42)
fmt.Printf("%10s\n", "초밥🍣맥주🍺")
fmt.Printf("%-10s\n", "초밥🍣맥주🍺")
}
42
42
초밥🍣맥주🍺
초밥🍣맥주🍺
#
기본 포맷과는 다른 출력을 합니다.
- 8진수 (
%#o
): 앞에0
을 붙입니다. - 16진수 (
%#x
): 앞에0x
를 붙입니다. - 16진수 대문자 (
%#X
): 앞에0X
를 붙입니다. - 포인터 (
%#p
): 앞의0x
를 생략합니다. %q
:strconv.CanBackquote
가true
를 반환하면 raw 문자열로 출력합니다.%e
,%E
,%f
,%F
,%g
,%G
: 항상 소수점을 표시합니다.%g
,%G
: 끝의0
을 생략하지 않습니다.%U
:U+0078 'x'
형태로 출력합니다.
package main
import (
"fmt"
)
func main() {
answer := 42
fmt.Printf("%o\n", answer)
fmt.Printf("%#o\n", answer)
fmt.Printf("%x\n", answer)
fmt.Printf("%#x\n", answer)
fmt.Printf("%X\n", answer)
fmt.Printf("%#X\n", answer)
fmt.Printf("%p\n", &answer)
fmt.Printf("%#p\n", &answer)
fmt.Printf("%q\n", "go")
fmt.Printf("%#q\n", "go")
fmt.Printf("%q\n", "`go`")
fmt.Printf("%#q\n", "`go`")
fmt.Printf("%.f\n", 12.345)
fmt.Printf("%#.f\n", 12.345)
fmt.Printf("%g\n", 12.345)
fmt.Printf("%#g\n", 12.345)
fmt.Printf("%U\n", answer)
fmt.Printf("%#U\n", answer)
}
52
052
2a
0x2a
2A
0X2A
0x416020
416020
"go"
`go`
"`go`"
"`go`"
12
12.
12.345
12.3450
U+002A
U+002A '*'
(공백)
- 숫자: 부호를 위한 공간을 한 칸 확보합니다.
- 바이트 단위 문자열 표현: 각 바이트 사이에 공백을 넣습니다.
package main
import (
"fmt"
)
func main() {
fmt.Printf("%d\n", 42)
fmt.Printf("% d\n", 42)
fmt.Printf("%x\n", "초밥🍣맥주🍺")
fmt.Printf("% x\n", "초밥🍣맥주🍺")
fmt.Printf("%X\n", "초밥🍣맥주🍺")
fmt.Printf("% X\n", "초밥🍣맥주🍺")
}
42
42
xec94a0eb b094f09f8da3 eb a7 b5 ec 9d bc eb 8d ba
ec 94 a0 eb b0 94 f0 9f 8d a3 eb a7 b5 ec 9d bc eb 8d ba
EC9490EB B094F09F8DA3 EB A7 B5 EC 9D BC EB 8D BA
EC 94 90 EB B0 94 F0 9F 8D A3 EB A7 B5 EC 9D BC EB 8D BA
0
공백 대신 0
으로 채웁니다.
- 숫자:
0
으로 채우는 위치는 부호 다음입니다.
package main
import (
"fmt"
)
func main() {
fmt.Printf("%10s\n", "초밥🍣맥주🍺")
fmt.Printf("%010s\n", "초밥🍣맥주🍺")
fmt.Printf("%10.3f\n", -12.345)
fmt.Printf("%010.3f\n", -12.345)
}
초밥🍣맥주🍺
00초밥🍣맥주🍺
-12.345
-00012.345
인덱스를 사용한 인자 지정 [n]
verb 앞에 [n]
을 사용하여 포맷할 인자의 인덱스를 지정할 수 있습니다. *
에도 적용 가능합니다.
[n]
을 지정하면 이후에는 n+1, n+2 번째 인자가 순서대로 사용됩니다.
package main
import (
"fmt"
)
func main() {
fmt.Printf("%[2]s %[1]s\n", "초밥🍣", "맥주🍺")
fmt.Printf("%[3]*.[2]*[1]f\n", 12.345, 2, 8)
fmt.Printf("%*.*f\n", 8, 2, 12.345)
fmt.Printf("%s %s %[1]q %q", "초밥🍣", "맥주🍺")
}
맥주🍺 초밥🍣
12.35
12.35
초밥🍣 맥주🍺 "초밥🍣" "맥주🍺"
'Go' 카테고리의 다른 글
Go 언어에서 chan chan 즉, 채널을 채널로 주고받기 (0) | 2024.09.19 |
---|---|
Go 실행 파일에 ZIP으로 리소스 임베딩하기: 간단하게 알아볼까요? (0) | 2024.09.19 |
Go로 CUI 툴을 쉽고 편하게! gocui 사용기 (0) | 2024.09.19 |
AriaSQL: Go 언어로 만든 새로운 관계형 데이터베이스의 탄생 (2) | 2024.09.07 |
Argon/Bcrypt가 CPU를 100% 사용하는 이유와 해결책 (2) | 2024.09.07 |