golang에서는 기본적으로 UTF-8 인코딩을 사용한다.
- 1~3 바이트 가변문자
- ANSI 코드와 1:1 대응이 되어 바로 변환
문자열이란 문자의 집합을 의미
타입:string
package main
import "fmt"
func main() {
// 1. 큰따옴표 사용
// 큰따옴표로 묶으면 특수문자 동작 (개행, 탭 등)
str1 := "Hello\t'world'\n"
// 2. 백쿼트 사용
// 백쿼트로 묶으면 특수문자가 동작하지 않음
str2 := `Go is "awesome"!\nGo is simple and\t 'powerful'`
// 여러줄에 걸쳐서 작성 가능
str3 :=
`Hello
My name is kang
Thank you :)
`
rune = int32 타입의 별칭 타입
package main
import "fmt"
func main() {
var char rune = '한'
fmt.Printf("%T\n", char) // char 타입 출력
// > int32
fmt.Println(char) // char 값 출력.
// > 54620
fmt.Printf("%c\n", char) // 문자 출력.
// > 한
}
문자 수가 아닌, 문자열이 차지하는 메모리 크기를 의미
package main
import "fmt"
func main() {
str1 := "가나다라마"
str2 := "abcde"
fmt.Println(len(str1))
// > 15
fmt.Println(len(str2))
// > 5
}
[]rune <-> string 은 상호변환이 가능하다.
package main
import "fmt"
func main() {
str := "abcde"
runes := []rune{97, 98, 99, 100, 101}
runes_to_str := string(runes)
str_to_runes := []rune(str)
fmt.Println(runes_to_str)
// > abcde
fmt.Println(str_to_runes)
// > [97 98 99 100 101]
}
package main
import "fmt"
func main() {
str1 := "가나다라마"
str1_to_runes := []rune(str1)
fmt.Println(len(str1))
// > 15 (바이트수)
fmt.Println(len(str1_to_runes))
// > 5 (글자수)
}
package main
import "fmt"
func main() {
str1 := "hello 월드!"
// str1_to_runes := []rune(str1)
// 1. 인덱스로 순회.
for i := 0; i < len(str1); i++ {
fmt.Printf("타입: %T, 값: %d, 문자: %c\n", str1[i], str1[i], str1[i])
}
// 타입: uint8, 값: 104, 문자: h
// 타입: uint8, 값: 101, 문자: e
// 타입: uint8, 값: 108, 문자: l
// 타입: uint8, 값: 108, 문자: l
// 타입: uint8, 값: 111, 문자: o
// 타입: uint8, 값: 32, 문자:
// 타입: uint8, 값: 236, 문자: ì
// 타입: uint8, 값: 155, 문자:
// 타입: uint8, 값: 148, 문자:
// 타입: uint8, 값: 235, 문자: ë
// 타입: uint8, 값: 147, 문자:
// 타입: uint8, 값: 156, 문자:
// 타입: uint8, 값: 33, 문자: !
}
package main
import "fmt"
func main() {
str1 := "hello 월드!"
// 2. rune 타입 변환 후 한글자씩 순회하기
str1_to_runes := []rune(str1)
// 1. 인덱스로 순회.
for i := 0; i < len(str1_to_runes); i++ {
fmt.Printf("타입: %T, 값: %d, 문자: %c\n", str1_to_runes[i], str1_to_runes[i], str1_to_runes[i])
}
// 타입: int32, 값: 104, 문자: h
// 타입: int32, 값: 101, 문자: e
// 타입: int32, 값: 108, 문자: l
// 타입: int32, 값: 108, 문자: l
// 타입: int32, 값: 111, 문자: o
// 타입: int32, 값: 32, 문자:
// 타입: int32, 값: 50900, 문자: 월
// 타입: int32, 값: 46300, 문자: 드
// 타입: int32, 값: 33, 문자: !
}
package main
import "fmt"
func main() {
str1 := "hello 월드!"
for _, v := range str1 {
fmt.Printf("타입: %T, 값: %d, 문자: %c\n", v, v, v)
}
// 타입: int32, 값: 104, 문자: h
// 타입: int32, 값: 101, 문자: e
// 타입: int32, 값: 108, 문자: l
// 타입: int32, 값: 108, 문자: l
// 타입: int32, 값: 111, 문자: o
// 타입: int32, 값: 32, 문자:
// 타입: int32, 값: 50900, 문자: 월
// 타입: int32, 값: 46300, 문자: 드
// 타입: int32, 값: 33, 문자: !
}
불변 = 일부만 변경할 수 없다.
package main
import "fmt"
func main() {
var str string = "hello world"
// 슬라이스로 복사. 단 주소값이 다름.
var slice []byte = []byte(str)
bytes[2] = 'a'
fmt.Println(str)
// > hello world
fmt.Printf("%s\n", bytes)
// > healo world
}
위의 경우 str
과 slice
의 주소값이 다르다. []byte 객체가 할당될때 기존 str에서 바이트단위로 하나씩 값을 복사해오는 형태로 옮겨진다. 그렇다면 실제 주소값을 확인해보자.
package main
import (
"fmt"
"reflect"
"unsafe"
)
func main() {
var str string = "hello world"
var slice []byte = []byte(str)
stringheader := (*reflect.StringHeader)(unsafe.Pointer(&str))
sliceheader := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
fmt.Printf("str:\t%x\n", stringheader.Data)
fmt.Printf("slice:\t%x\n", sliceheader.Data)
}