예제코드
package main import ( "fmt" "regexp" ) func main() { match, _ := regexp.MatchString("p[a-z]+ch", "peach") fmt.Println(match) r, _ := regexp.Compile("p([a-z]+)ch") fmt.Println(r.MatchString("peach")) fmt.Println(r.FindString("peach")) fmt.Println(r.FindStringIndex("hel peach")) fmt.Println(r.FindStringSubmatch("punch")) fmt.Println(r.FindAllString("peach punch pinch", -1)) fmt.Println(r.ReplaceAllString("peach po pinch", "xxx")) } 결과
true true peach [4 9] [punch un] [peach punch pinch] xxx po xxx
임베딩(Embedding)에 대해 알아보자.
자바의 상속과는 달리, Golang은 임베딩을 지원한다.
Effective java를 보면 ‘상속 대신 조합(composition)을 하라’라고 하는데 여기의 조합과 임베딩은 유사한 개념이다.
참고로 상속은 부모-자식간 강한 커플링을 맺게 되므로 좋지 않다. 조합은 내부 구성품에 접근하기 위한 getter/setter가 필요하지만 임베딩은 이조차 필요없이 흡수(?)가 된다는 면에서 차이가 있다. interface와 struct 모두 임베딩이 가능하다. 단,
interface는 interface만 포함할 수 있다. struct는 struct과 interface 둘 다 포함할 수 있다. 임베딩을 하게 되면 안쪽에 있는 메소드를 바깥쪽에서 마음데로 가져다 쓸 수 있다.
피보나치를 일꾼 4명에게 동시에 계산하도록 만들어보자.
설명 worker는 일꾼이고 모두 goroutine으로 실행된다. jobs와 results는 각각 작업들과 결과물들을 전달하는 buffered 채널이다. worker 내부에는 jobs 채널로 부터 일을 계속 수신하고 그 결과는 results 채널로 전달한다. jobs 채널에 0~99까지의 작업을 전달한다. jobs에는 총 100개의 작업을 전달하고 jobs 채널을 종료(close)한다. 메인 스레드는 results 채널에서 오는 결과를 기다리고 있다. 코드 func main() { jobs := make(chan int, 100) results := make(chan string, 100) for i := 0; i < 100; i++ { jobs <- i } close(jobs) go worker(1, jobs, results) go worker(2, jobs, results) go worker(3, jobs, results) go worker(4, jobs, results) for i := 0; i < 100; i++ { fmt.
Goroutine goroutine은 경량 스레드이다.
(Green thread 혹은 light-weight thread 라고도 부른다)
green threads are threads that are scheduled by a runtime library or virtual machine (VM) instead of natively by the underlying operating system (OS). - Wikipedia
Channel channel은 데이터를 보내는 통로이다.
자료구조 queue의 목적으로 써도 문제가 없다.
버퍼 사이즈를 명시하지 않으면 사이즈가 0이다.
ch1 := make(chan int) // 버퍼 사이즈가 0 ch2 := make(chan int, 1024) // 버퍼 사이즈가 1024 동작 방식 처음 goroutine을 사용하다보면 아래와 같은 에러를 자주 보게 된다.
Golang에서 Stack과 Queue 자료구조를 사용해보자.
다행히 Slice만으로도 두 가지 용도로 사용할 수 있다.
Stack 코드
// push stack := []int{1, 2, 3} stack = append(stack, 4) stack = append(stack, 5, 6) fmt.Println(stack) // pop val, stack := stack[len(stack)-1], stack[:len(stack)-1] fmt.Println(stack, val) 결과
[1 2 3 4 5 6] [1 2 3 4 5] 6 Queue 코드
// enqueue queue := []int{1, 2, 3} queue = append(queue, 4) fmt.
Value receiver와 Pointer receiver, 2가지가 receiver가 있다.
아래와 같은 구조체가 있다고 가정하고
type Person struct { Name string } Value receiver의 예
func (p Person) String() string { return p.Name + "!!!" } Pointer receiver의 예
func (p *Person) String() string { return p.Name + "!!!" } 두 가지 receiver를 언제 어떻게 사용해야하는지 헷갈려서 공부한 내용을 기록한다.
우선 아래의 원칙을 알아야 한다.
원칙1. 둘 중에 한 가지만 정의할 수 있다.
1. 간단하다. 25개 키워드. 끝. (https://golang.org/ref/spec#Keywords) Java 49개 (https://www.geeksforgeeks.org/list-of-all-java-keywords/) c++17 84개 (https://boycoding.tistory.com/140) => 배우기 쉽고 읽기도 쉽다. 2. 성능이 좋다 Java 대비 빠른 실행속도 및 훨씬 적은 메모리 사용 (https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/go.html) binary 빌드 & 배포가능. no runtime environment! => 서버 운영비용 감소 3. 훌륭한 생태계 docker, kubernetes, prometheus와 같은 유명한 SW존재 오픈소스도 활발하게 개발되고 있음 Google (https://github.com/google) Netflix (https://github.com/Netflix) Grab (https://github.com/grab) Uber (https://github.com/uber) Golang Korea (https://web.facebook.com/groups/golangko/) 관심도 증가 중(https://trends.