본문으로 바로가기

이번 글 목차


1. Example 테스트

2. 문자열

3. 배열과 슬라이스

 

 

Example 테스트?


1. Example 테스트 만드는 법

 

1) 테스트 파일_test 를 붙여야 합니다.

2) 함수의 이름은 반드시 Example 로 시작해야 합니다.

3) 'go test 디렉토리명/~_test.go' 명령어를 수행하면 됩니다.

4) 맨 아래 예상 결과 값을 작성해줘야 됩니다.

- '// Output:' 을 써주고 예상 출력값을 아래 써주면 됩니다.

package learngo_test

import (
	"fmt"
	"strings"
)

func lenAndUpper(name string) (int, string) {
	return len(name), strings.ToUpper(name)
}

func Example_lenAndUpper() {
	fmt.Println(lenAndUpper("Brenden's Blog"))
	fmt.Println(lenAndUpper("Brenden Hong"))
	// Output:
	// 14 BRENDEN'S BLOG
	// 12 BRENDEN HONG
}

 저는 Visual Studio Code에서 작성 중이며, 아래와 같은 결과 화면이 노출됩니다.

 

 

문자열은?


1. 개요

1) string이라는 자료형을 이용하며 읽기 전용입니다.

2) Go 언어의 소스 코드는 UTF-8로 되어 있다.

3) 실제 바이트 표현이 어떤지를 중시하거나 수정이 필요하다면 []byte를 쓰는 것이 가능하다.

func Example_byteToString() {
	b := []byte("브랜든")
	b[2]++
	fmt.Println(string(b))
	// Output:
	// 븍랜든
}

4) string, strconv  두 개의 패키지로 대부분의 문자열 조작이 가능하다.

 

2. 문자열 이어보기

func Example_strings() {
	name := "brenden"
	sns := "blog"

	fmt.Println(name + " " + sns)
	fmt.Println(fmt.Sprint(name, " ", sns))
	fmt.Println(strings.Join([]string{"brenden", "blog"}, " "))

	s := make([]string, 0)
	s = append(s, name, sns)
	fmt.Println(strings.Join(s, " "))

	// Output:
	// brenden blog
	// brenden blog
	// brenden blog
	// brenden blog
}

위와 같은 4가지 방법으로 간단히 문자열을 이어볼 수 있습니다.

 

3. 문자열 숫자로 바꿔보기

func Example_stringToInt() {
	s := "360"

	i, err := strconv.Atoi(s)
	fmt.Println(i, err)

	i1, err1 := strconv.ParseInt(s, 10, 64)

	fmt.Println(i1, err1)

	// Output:
	// 360 <nil>
	// 360 <nil>
}

 

 

배열과 슬라이스


1. 배열과 슬라이스

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

2) 차이점 : 배열은 크기가 정해져 있고, 슬라이스는 크기가 정해져 있지 않습니다. 그래서 보통 슬라이스를 많이 쓰게 되실 겁니다.

// 배열
fruits := [3]string{"사과","배","귤"}

// 슬라이스
names := []string{"브랜든", "brenden", "브랜든 홍"}
// 컴파일러가 배열의 크기를 알아내게 하는 방법 '...'
names := [...]string{"브랜든", "brenden", "브랜든 홍"}

 

2. 슬라이스 더 알아보기!

슬라이스는 길이용량을 갖고 있고 길이가 변할 수 있는 자료구조입니다.

빈 슬라이스에는 nil 값이 들어갑니다.

names := make([]string, 3)
names[0] = "브랜든"
names[1] = "brenden"
names[2] = "브랜든 홍"

make로 n이라는 크기로 만든 슬라이스는 해당 자료형의 기본값이 들어갑니다.

(문자열 : "", 정수 : 0)

 

func Example_slice() {
	nums := []int{1, 2, 3, 4, 5}
	fmt.Println(nums)
	fmt.Println(nums[1:2])
	fmt.Println(nums[2:])
	fmt.Println(nums[:4])

	// Output:
	// [1 2 3 4 5]
	// [2]
	// [3 4 5]
	// [1 2 3 4]
}

파이썬 슬라이스와의 차이점은 Go에서는 음수를 사용할 수 없다.

맨 뒤에 값을 제외하고 싶을 때 names[:-1]과 같이 쓸 수 없고, 'names[:len(names)-1]' 와 같이 쓰면 된다.

 

범위가 넘어가면 패닉이 발생한다. 패닉은 java에서의 exception과 비슷하지만 적극적으로 활용되지는 않는다.

에러를 반환할 수 있는 경우에는 패닉보다는 에러를 반환하는 식으로 개발한다.

 

 

1) 슬라이스 덧붙이기

func Example_slice_append() {
	nums := []int{1, 2, 3, 4, 5}

	nums = append(nums, 6)
	fmt.Println(nums)

	// append는 가변인자를 받는다.
	nums = append(nums, 7, 8)
	fmt.Println(nums)

	nums1 := []int{9, 10}
	nums = append(nums, nums1...)
	fmt.Println(nums)

	// Output:
	// [1 2 3 4 5 6]
	// [1 2 3 4 5 6 7 8]
	// [1 2 3 4 5 6 7 8 9 10]
}

3번째에 예제에 또 다른 슬라이스 내에 있는 값을 이어 붙이고 싶을 때 (...) 을 쓰면 내부 값을 늘어놓듯이 삽입이 가능합니다.

 

2) 슬라이스 용량

func Example_slice_cap() {
	nums := []int{1, 2, 3, 4, 5}

	fmt.Println(nums)
	fmt.Println("len:", len(nums))
	fmt.Println("cap:", cap(nums))

	slice1 := nums[:3]
	fmt.Println(slice1)
	fmt.Println("len:", len(slice1))
	fmt.Println("cap:", cap(slice1))

	slice2 := nums[2:]
	fmt.Println(slice2)
	fmt.Println("len:", len(slice2))
	fmt.Println("cap:", cap(slice2))

	// Output:
	// [1 2 3 4 5]
	// len: 5
	// cap: 5
	// [1 2 3]
	// len: 3
	// cap: 5
	// [3 4 5]
	// len: 3
	// cap: 3
}

결과값을 보시면 알겠지만 슬라이스를 사용하면 어느정도 용량(cap)을 쓸 건지를 지정하게 됩니다.

위의 경우 cap이 5가 잡히게 되며, 슬라이스를 3만큼 짜르게 되더라도 len은 줄고 cap은 유지되는 걸 보실 수 있습니다.

슬라이스는 연속된 메모리를 사용하며, 남는 자리가 없을 때 덧붙이려고 하면 새로운 메모리 공간으로 이동된다고 보시면 됩니다.

// 길이는 3 용량은 5인 슬라이스 만드는 방법
//(1번 방법)
nums := make([]int, 3, 5)

//(2번 방법)
nums := make([]int, 5)
nums = nums[:3]

위와 같이 쓰는 이유는 미리 공간을 예약해 두기 위해서 입니다. 즉 N개까지 길이가 늘어나더라도 복사가 일어나지 않게 하기 위해서 입니다.

 

슬라이스는 시작 주소, 길이, 용량 으로 구성됩니다.

nums := append(nums, 10)

append의 길이값이 변경된 슬라이스를 리턴받지 않으면 컴파일 오류가 발생됩니다.

 

 

3) 슬라이스 복사

func Example_slice_copy() {
	src := []int{1, 2, 3, 4, 5}
	//Copy하는 방법 1
	dest := make([]int, len(src))

	for i := range src {
		dest[i] = src[i]
	}

	fmt.Println(dest)
	//Copy하는 방법 2
	dest2 := make([]int, len(src))
	copy(dest2, src)

	fmt.Println(dest2)

	//Copy하는 방법 3
	dest3 := append([]int(nil), src...)
	fmt.Println(dest3)

	// Output:
	// [1 2 3 4 5]
	// [1 2 3 4 5]
	// [1 2 3 4 5]
}

 

 

4) 슬라이스 삽입 및 삭제 (*** 중요 ***)

 

이 부분은 확실히 이해하고 넘어가야 됩니다.

삽입과 삭제 메서드가 제공되지 않거든요....

(실제로 연속된 공간에 있어야 하므로 굉장히 비효율적인 과정을 거칠 수 밖에 없습니다.)

 

- a 슬라이드의 i번째 원소로 x를 삽입하는 방법은?

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

[0, 1, 2 ... , i-1, i], [i, i+1 ...]의 두 배열이 합쳐지게 됩니다.

[0, 1, 2... , i-1, i, i, i+1, ...]

[0, 1, 2... , i-1, x, i, i+1, ...]

 

위와 같은 순서로 값이 삽입되게 됩니다. 

다만, 맨 앞이나 중간에 끼워넣는 경우에만 사용이 가능합니다.

 

즉 i의 범위가 len(a)-1 까지만 가능하기 때문에 마지막에 덧붙이는 작업 때문에 아래와 같이 코드를 변경해야됩니다.

if i < len(a) {
	a = append(a[:i+1], a[i:]...)
	a[i] = x
} else {
	a = append(a, x)
}

 

아래와 같은 코드로도 가능합니다.

1번째 줄에 있는 x 값은 어떤 값이든 상관없습니다. 왜냐하면 단순하게 슬라이스의 크기만 늘려준 것이기 때문입니다.

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

예를 들어서 'a := []int{1, 2, 3, 4, 5}' 라고 한고, i=2에 있는 값을 10으로 바꾸고자 한다면 아래와 같은 순서로 변하게 됩니다.

1 line : [1 2 3 4 5 10]

2 line : [1 2 3 3 4 5]

3 line : [1 2 10 3 4 5] 

 

2번째 line이 가장 헷갈리실텐데 copy함수는 두 슬라이스 중 짧은 슬라이스 길이만큼을 복사하는 특징을 가지고 있습니다.

[4 5 10] 자리에 [3 4 5 10]을 넣으려고 하는데 3칸 밖에 없으므로 [3 4 5]만 들어가게 됩니다. (10은 길이 때문에 들어가지지 않는다.)

 

// x := []int{7, 8, 9}
a = append(a, x...)
copy(a[i+len(x):], a[i:])
copy(a[i:], x)

위 같은 코드를 사용하시면 여러 개 삽입도 가능합니다!

 

위 개념을 완벽히 이해하셨다면 삭제는 더 쉬울꺼예요~

i번째에 있는 값을 건너 뛴다라고 생각하면됩니다. 시간 복잡도는 O(n)입니다.

// 1개를 삭제할 경우
a = append(a[:i], a[i+1:]...)

// k개를 삭제할 경우
a = append(a[:i], a[i+k:]...)

 

순서가 바뀌어도 된다면 O(1)의 방법도 있습니다.

// 맨 마지막 값을 삭제하고자 하는 값에 대입해주고 슬라이스의 맨 마지막 값 뺀 슬라이스로 교체
a[i] = a[len(a)-1]
a = a[:len(a)-1]

// 연속된 k 개를 지우는 방법
// 시간 복잡도는 O(k)
start := len(a) - k
if i+k > start {
	start = i + k 
}
copy(a[i:i+k], a[start:])
a = a[:len(a) - k]

 

삭제할 때 중요한 건 슬라이스 내부에 포인터가 있으면 가비지 컬렉션이 일어나지 않기 때문에 메모리 누수가 발생한다. 그러므로 삭제 뒤 공간은 nil로 지워줘야 합니다. 구조체를 빈 구조체로 덮어쓰거나 해줘야 됩니다.

 

Go언어 기초 (문자열, Example 테스트, 자료구조(배열, 슬라이스 추가/삽입/삭제/용량))


댓글을 달아 주세요