Go Functional Options Pattern

함수형 옵션 패턴 (Functional Options Pattern) 함수형 옵션 패턴은 함수가 선택적 인수를 허용하는 함수형 프로그래밍 에서 유래했다. 함수형 옵션 패턴을 사용하여 기존 함수 구조를 손상시키지 않고 확장할 수 있는 유여한 인터페이스를 제공한다. Go에서는 구조체를 단순화 하기 위해서 사용하며 서로 다른 매개변수를 가진 많은 생성자를 정의하는 대신 다양한 함수 옵션을 허용하여 단일 생성자를 정의할 수 있다. type ClientOptions struct { Url string Port int Method string } type Option func(*ClientOptions) error func WithUrl(url string) Option { return func(co *ClientOptions) error { co.Url = url return nil } } func WithPort(port int) Option { return func(co *ClientOptions) error { co.Port = port return nil } } func WithMethod(method string) Option { return func(co *ClientOptions) error { co.Method = method return nil } } func NewClient(opts ...Option) (*ClientOptions, error) { var co ClientOptions for _, opt := range opts { err := opt(&co) if err != nil { return nil, err } } return &co, nil } func main() { client, err := NewClient(WithUrl("http://localhost"), WithPort(8080), WithMethod("GET")) if err != nil { panic(err) } log.Println(client.Port) log.Println(client.Url) log.Println(client) } 결론 함수형 옵션 패턴은 가변적인 파라메터가 있을때 생성자 함수의 로직을 단순화 하고 유지 보수성을 높여 줄수 있다. 기존 코드의 변경 없이 옵션을 추가할 수 있으므로 재사용성이 높은 코드를 작성 할 수 있다. ...

March 1, 2024 · 1 min · 210 words · Hillfolk

Go 에서 적합한 리시버 타입의 결정 하기

Go에서 적합한 리시버 타입 결정하기 Go를 사용하다 보면 메서드 리시버로 값을 사용할지, 포인터를 사용할지 고민하는 경우가 많습니다. 최근 읽은 책에서 이에 대해 명확한 기준을 제시한 내용이 있어 공유하려 합니다. 대부분 익숙한 내용일 수 있지만, 이렇게 체계적으로 정리하니 고민을 줄이고 새로운 관점도 얻을 수 있어 유용했습니다. 리시버가 반드시 포인터여야 하는 경우 리시버의 값을 변경해야 하는 경우 가장 단순한 케이스로, 메서드에서 리시버의 값을 수정해야 할 때입니다. 예를 들어, 리시버가 슬라이스인 경우 메서드 내에서 원소를 추가하거나 수정해야 한다면 포인터 리시버가 필요합니다. ...

February 26, 2024 · 2 min · 273 words · Hillfolk

Go 동시성 프로그래밍 하기

Goroutine 고루틴은 함수를 동시에 실행시키는 기능이다. 다른 언어의 쓰레드보다 운영체제의 리소스를 적게 사용한다. 클로저 클로저를 고루틴으로 실행할 때 반복문에 의해 바뀌는 변수는 반드시 매개변수로 넘겨 준다. 멀티코어 활용 체널 사용 채널은 고루틴끼리 정보를 교환하고 실행의 흐름을 동기화하기 위해 사용한다. 채널 생성시 보내기 전용 이나 받기 전용으로 생성 가능한다. package main import "fmt" func sum(a int, b int, c chan int) { c <- a + b } func main() { c := make(chan int) go sum(1 ,2 ,c) n := <-c fmt.Println(n) } range close 사용하기 close 는 채널을 닫을 수 있으며 이미 닫은 채널을 닫게되면 패닉 발생 채널을 닫으면 range 루프가 종료 됩니다. 채널이 열려 있고 값이 들어 오지 않으면 range 는 실행되지 않고 계속 대기 한다. package main import "fmt" func main() c:= make(chan int) go func() { for i := 0; i >5 i++{ c <- i // 채널에 값을 보냄 } close(c) }() for i:= range c { fmt.Println(i) } } Select 사용하기 Go 언어는 여러 채널을 손쉽게 사용할 수 있도록 select 분기문을 지원 select문은 지정한 채널의 데이터가 있을 경우 case 수행한다. select문에서는 지정한 체널에 데이터를 보내는 case는 항상 수행 된다. for{ case c1 <- 10: // 매번 체널 c1 에 값을 보냄 case s:= <-c2: // c2 값이 들어 왔을때는 값을 꺼낸뒤 s에 대입 } 동기화 객체 Mutex: 뮤텍스 ,상호 배제, 공유 데이터 보호에 주로 사용 RWMutex: 읽기/쓰기 뮤텍스 입니다. 일기와 쓰기 동작을 나누어서 잠금을 걸수 있습니다. Cond: 조건 변수 (condition variable) 입니다. 대기하고 있는 하나이상의 객체를 깨울수 있다. Once: 특정함수를 딱 한번만 실행할때 사용합니다. Pool: 멀티 쓰레드 (고루틴)에서 사용할 수 있는 객체풀 입니다. 자주 사용하는 객체를 풀에 보관하여 사용가능 하다. WaitGroup:고루틴이 모두 끝날 때까지 기다리는 기능 Atomic: 원자적 연산이라고도 하며 더 이상 쪼갤 수 없는 연산 의미 고루틴에서 안전하게 값을 연산하는 기능 입니다.

May 3, 2019 · 2 min · 289 words · Hillfolk

Go Messaging System

Nats Message Echo System Intro Nats Server는 IoT 메시징 및 마이크로 서비스 아키텍처를 위한 간단하고 고성능의 오픈소스 메시징 시스템 입니다. go로 작성되어 있으며 Python, Java, Ruby, Node.js 등으로 작성된 클라이언트가 있습니다. NATS Design Goals The core principles underlying NATS are performance, scalability, and ease-of-use. Based on these principles, NATS is designed around the following core features: Highly performant (fast) Always on and available (dial tone) Extremely lightweight (small footprint) Support for multiple qualities of service (including guaranteed “at-least-once” delivery with NATS Streaming) Support for various messaging models and use cases (flexible) Pub Code var urls = flag.String("s", nats.DefaultURL, "The nats server URLs (separated by comma)") log.SetFlags(0) flag.Usage = usage flag.Parse() args := flag.Args() if len(args) < 2 { usage() } nc, err := nats.Connect(*urls) if err != nil { log.Fatal(err) } defer nc.Close() subj, msg := args[0], []byte(args[1]) for { nc.Publish(subj, msg) nc.Flush() } if err := nc.LastError(); err != nil { log.Fatal(err) } else { log.Printf("Published [%s] : '%s'\n", subj, msg) } Sub Code var urls = flag.String("s", nats.DefaultURL, "The nats server URLs (separated by comma)") var showTime = flag.Bool("t", false, "Display timestamps") log.SetFlags(0) flag.Usage = usage flag.Parse() args := flag.Args() if len(args) < 1 { usage() } nc, err := nats.Connect(*urls) if err != nil { log.Fatalf("Can't connect: %v\n", err) } subj, i := args[0], 0 nc.Subscribe(subj, func(msg *nats.Msg) { i += 1 printMsg(msg, i) }) nc.Flush() if err := nc.LastError(); err != nil { log.Fatal(err) } log.Printf("Listening on [%s]\n", subj) if *showTime { log.SetFlags(log.LstdFlags) }

May 2, 2019 · 2 min · 248 words · Hillfolk

Go Cobra 사용하기

Cobra는 강력한 Cli 라이브러리로서 Go 기반에서 구동된다. 해당 모듈은 docker, kubernetes, hugo 등에서 사용될 정도로 안정적인 라이브러리 이다. cobra github Install go get을 이용해서 package를 설치하고 코드에 import 해준다. go get -u github.com/spf13/cobra/cobra import "github.com/spf13/cobra" Cobra Generator Cobra Generator를 사용하면 손쉽게 Cobra를 적용할수 있다. cobra 팩키지가 설치된 경우 자동으로 cobra 프로젝트를 추가하거나 Command을 추가하는 명령을 사용할 수 있다. Generator는 $GOPATH 하위 리소스에서 사용가능하다. 초기화 init 명령으로 cobra에게 적합한 프로젝트 구성 및 자동으로 cobra 코드를 생성해 준다. ...

May 1, 2019 · 1 min · 121 words · Hillfolk