[디스커버리 Go] - 문자열 및 자료구조

문자열

유니코드 처리

  • GO는 기본적으로 UTF-8 인코딩
for i, r :=range "가나다" {
fmt.Println(i, r, string(r))
}
fmt.Println(len("가나다"))
//Output:

//0 44032 가

//3 45208 나

//6 45796 다

//9

-> 한글이 unicode가 3byte이기 때문

테스트

go run 대신 go test 파일명으로 실행
그러면 Output으로 주석밑의 부분 코드를 비교

바위트단위로 출력

s := "가나다"
fmt.Printf("%x\n", s)
//Output:

//eab080eb8298eb8ba4

읽기 전용이기 떄문에 바이트를 조작하는것은 불가능
그러나 바이트 단위의 슬라이스로 변환하면 가능.

b:= []byte("가나다")
b[2]++
fmt.Println(string(b))
//Output:

//각나다

패키지 문서

https://golang.org/pkg/

문자열

s := "abc"
ps := &s
s += "def"
fmt.println(s)
fmt.println(*ps)
strconv.Atoi("350")
.ParseInt
.ParseFloat
.Itoa

배열과 슬라이스

배열

연속된 메모리 공간을 순차적으로 이용하는 자료구조

fruits := [3]string{"사과", "바나나", "토마토"}

Go에서는 배열은 자주 쓰이지 않음. 왜냐하면 더 유연한 구조의 슬라이스가 있기 때문.

슬라이스

위 배열 초기화 코드에서 3만 빼면 슬라이스. 배열은 크기가 자료형에 고정이지만 슬라이스는 길이와 용량을 갖고 있고 길이가 변할 수 있는 구조

var fruits []string

빈슬라이스에는 nil이라는 값이 들어감.
빈 스트링을 가진 n의 크기의 슬라이스를 만드려면 make함수를 쓰면 됨

fruits := make([]string, n)

슬라이스는 이름답게 자르는게 유연함 (단, 음수는 안됨)

num := []int{1,2,3,4,5}
fmt.Println(nums)
fmt.Println(nums[1:3])
fmt.Println(numsnums[2:])
fmt.Println(nums[:3])
//Output:

//[1 2 3 4 5]

//[2 3]

//[3 4 5]

//[1 2 3]

append를 사용해서 덧붙이는게 가능 (add처럼), 배열끼리는 가변인자로

fruits = append(fruits, '포도')
f2 := []string{"포도", "딸기"}
f3 := append(f1, f2...)

슬라이스는 자료구조상 연속된 메모리 구조라 자리가 없는데 더 늘어나면 더 넓은 메모리 공간으로 복사됨.
뒤를 잘라내면 길이는 줄지만 용량은 그대로. 앞을 잘라내면 용량도 줄어듬. 잘라진 슬라이스들은 모두 동일 메모리를 봄. 그래서 뒤를 자르면 잘렸어도 복원이 가능함

len(slice) //길이 

cap(slice) //용량

nums := make([]int, 3, 5) //5는 용량

슬라이스는 배열이기 때문에 용량이 늘어나면 주소를 옮겨서 복사함 그래서 append같은 함수는 복사된 배열을 반환. 그래서 값을 새로 받아야함. (안받으면 컴파일 오류)

슬라이스 복사는 copy함수를 씀, 두 배열의 길이가 다르면 더 작은쪽으로 복사. 그래서 전체를 복사하고 싶으면 아래 코드와 같이 해야함

copy(dest, src) //반환값은 몇개가 복사되었는지 


src := []int{1,2,3,4,5}
dest := make([]int, len(src))
copy(dest, src)

그냥 dest := src 이렇게 할 경우 포인터까지 모두 복사.

슬라이스 삽입 (특정위치에)

넣고자 하는 i위치를 기준으로 배열을 쪼개서 i번째의 값이 두번 있도록 붙인 다음에
그중 하나의 i에 x값을 넣어줌 맨 오른쪽에 붙이려면 예외처리 해야함

a = append(a[:i+1], a[i:]...)
a[i] = x

또다른 방법은 append를 해서 길이를 늘린다음에 복사를 해서 이동시킨다

a = append(a, x)
copy(a[i+1:], a[i:])
a[i] = x
슬라이스 삭제

지울 부분을 빼고 슬라이스를 잘라내서 붙인다.

a = append(a[:i], a[i+k])
copy(a[i:], a[i+k:])

슬라이스를 삭제 할 때는 삭제되는 내부에 포인터가 남아있는지 잘 봐서 누수가 일어나지 않도록 해야함

copy(a[i:], a[i+k:])
for i := 0; i < k; i++ {
a[len(a)-1-i] = nil
}
a = a[:len(a)-k]

스택

스택은 따로 있지 않고 슬라이스로 구현해야함. 이미 여러 라이브러리들이 있고 책 91쪽의 코드 참조.

golibs/stack - A LIFO and ringbuffer package

stackgo - A fast slice-based stack implementation

go lane

m := make(map[keyType]valueType)
m := map[keyType]valueType{}

value, ok := m[key]
//두번째 변수는 해당 키 값이 존재하는지에 대한 bool값 


m[key] = value

delete(m, key)

순서가 없지만 상수 시간에 값을 찾ㅇ르 ㅅ ㅜ있ㅇ므
go map에는 같은키가 여러번 들어가는건 스레드가 안전하지 않아서 안된다. 쓰려면 외부라이브러리를 써야함

입출력

파일 읽기, 쓰기

f, err := os.Open(filename)
if err != nil {
return err
}
defer f.Close()
var num int
if _, err := fmt.Fscanf(f, "%d\n", &num); err == nil {
//num 변수 사용 

}

if _, err := fmt.Fpintf(f, "%d\n", num); err != nil {
return err
}

defer는 해당 함수를 벗어날 경우 호출됨

bufor.Scanner를 사용할 수도 있음

이 포스트는 디스커버리 Go를 읽고 정리한 내용입니다.
http://www.yes24.com/24/Goods/24759320?Acode=101

Comments

comments powered by Disqus
comments powered by Disqus