20250116

패키지 만들고, 패키지 가져와 사용하기 -golnag

패키지 만들고, 패키지 가져와 사용하기 -golnag


package(패키지)를 만들때

- 프로젝트 폴더안에, 디렉토리를 하나 생성합니다.(mkdir mypkg)

- 디렉토리 이름은, 만들 패키지 파일이름(mypkg.go)과 같아야 합니다.(import 하기 편함)

  디렉토리이름, 패키지이름 이 일치해야, 에러없는 함수 호출이 가능합니다.

- 패키지 폴더이름 및 파일이름은, 내용을 이해하기 쉬운 이름으로 생성.

// mypkg/mypkg.go 관리하기 편하게 만든 폴더안에, 같은 이름으로
package mypkg //여기 이름과, 실제 파일이름이 같아야 문제발생이 없습니다.

import "fmt" //출력관련 패키지 불러오기

// 패키지에서 사용할 함수, Hello에 첫글자가 대문자여야 외부노출 됩니다.
func Hello(name string) {
fmt.Printf("Hello, %s!\n", name)
}

- 패키지 파일을 저장합니다.


package(패키지)를 가져와서 사용할때

// main.go
package main

import (
"프로젝트폴더이름/mypkg" // 패키지 경로. 프로젝트이름(폴더)가 test1 이면, "test1/mypkg"
// 프로젝트폴더 안에 mypkg폴더안에서 찾으라는 뜻
)

func main() {
mypkg.Hello("Go Dev") // 패키지 함수 호출방법: 패키지파일이름.첫글짜 대문자 함수
}

파일을 먼저 저장합니다.

go mod init 프로젝트이름(프로젝트폴더이름)

go mod tidy

go run main.go


문제 발생시: 프로젝트폴더 안에 go.mod 파일을 열어서, 프로젝트 이름 체크

module test1 // 프로젝트 폴더 또는 프로젝트이름

go 1.22.2


디렉토리 구조

프로젝트폴더이름(test1) / main.go

프로젝트폴더이름(test1) / go.mod

프로젝트폴더이름(test1) / mypkg 폴더

프로젝트폴더이름(test1) / mypkg 폴더 / mypkg.go






20250114

init함수, main함수 관련 - golang

init함수, main함수 관련 - golang

init 함수는 패키지 초기화 작업을 위해 사용됩니다.

- init 함수는 패키지가 처음 로드될 때 자동으로 호출됩니다.

- init 함수는, main함수보다 아래에 있던, 위에 있던, 먼저 실행됩니다.

- init함수는 가독성을 위해서, 관례상, 예의상 main함수보다 위에 배치합니다.

- 명시적으로 호출할 수 없습니다.(자동호출됨. 개발자가 직접 호출은 못함)

- 패키지 내 init 함수는 파일 상단에서 아래로, 왼쪽에서 오른쪽 순서로 실행됩니다.

- 패키지 의존 관계에 따라 import된 순서대로 실행됩니다.

- 너무 많은 init 함수는 코드 가독성을 떨어뜨릴 수 있고, init함수는 단순 초기화 작업만 담당.

- init 함수는 자동 실행되므로, 예상치 못한 동작을 디버깅하기 어려울 수 있습니다.


init 함수는 함수처럼 선언하지만, 파라미터나 반환값이 없습니다.

func init() {
// 초기화 코드
}

- 하나의 파일에 init 함수를 여러 개 정의할 수 있습니다.

- 같은 패키지 내의 파일에 각각 init 함수를 정의할 수도 있습니다.

// 패키지 초기화: 변수 초기화 또는 외부 데이타베이 연결

func init() {
globalVar = 42
fmt.Println("패키지 초기화 완료!")
}

의존성 처리: 패키지가 의존하는 리소스 또는 설정을 준비.

// 검증작업: 패키지 설정이나 환경 변수를 확인

func init() {
if os.Getenv("APP_ENV") == "" {
log.Fatal("APP_ENV 환경 변수가 필요합니다!")
}
}


main 함수는 프로그램의 시작점으로, 실행 로직을 포함합니다.

- main 함수는 Go 프로그램의 시작점이자 핵심 실행부입니다.

Go 런타임은 프로그램 실행 시 main 패키지의 main 함수를 찾아 실행합니다.

- main 함수는 프로그램 실행의 시작점입니다. 1개만 있어야 함.

- main 함수는 프로그램 실행의 시작점입니다.

- main 함수는 프로그램 실행의 시작점입니다.

- 프로그램의 진입점 입니다.

- Go 프로그램은 반드시 하나의 main 패키지를 가져야 하며, main 패키지의 main 함수가 실행됩니다.

- main 함수는 프로그램 실행 시 호출되는 첫 번째 함수입니다(단, init 함수가 먼저 실행된 뒤 호출).

- 필수 함수 입니다.

- main 함수는 프로그램 실행을 위해 반드시 정의해야 합니다.

- 정의하지 않으면 컴파일 오류가 발생합니다.

- main 함수는 반드시 main 패키지에만 존재할 수 있습니다.

- 다른 패키지에서는 main 함수 이름을 사용할 수 없습니다.

// 반환값이 없고, 매개변수를 받지 않습니다.

func main() {
// 프로그램 실행 로직
}

- 다른 패키지를 호출하거나 사용하는 작업을 수행합니다.

- 전체 프로그램의 실행 흐름을 제어합니다.

- main 함수가 호출되기 전에 필요한 초기화 작업은 init 함수에서 처리됩니다.

package main // Go 프로그램은 반드시 하나의 패키지에서 시작해야 합니다.
// main 패키지는 Go 프로그램의 진입점 역할을 합니다.

import ( // 외부 패키지를 현재 파일에 가져오는 데 사용됩니다.
"fmt" // fmt는 표준 라이브러리 중 하나로, 데이터를 출력하거나 형식을 지정하는 기능
)

func init() {
fmt.Println("init 함수 실행")
}

func main() {
fmt.Println("main 함수 실행")
}

- main 함수는 반환값을 가질 수 없습니다. 즉, func main() int는 불가능합니다.

- 다른 함수처럼 main()을 호출할 수 없습니다.

- 하나의 프로그램에서 main 함수는 하나만 정의할 수 있습니다.












20250113

클로저(closure) 에 대하여 - golang

클로저(closure)의 개념

클로저는 함수가 외부 환경의 변수를 캡처하여 기억하는 기능입니다.

- 함수 + 지역변수 값 = 변수에 저장해두는 개념 입니다.

값을 기억하고 있는, 함수라고 말할수 있습니다. return되는 함수를(공식을) 들고 있는 변수 개념.

클로저는 함수와 해당 함수가 선언된 환경(context)을 함께 저장하는 구조입니다.

함수가 외부 함수의 변수(지역 변수 포함)를 기억하고 사용할 수 있습니다.

클로저로 만들어진 함수는 호출될 때마다 상태를 유지합니다.

intSeq 함수에서 반환된 익명 함수 intSeq 내부의 지역 변수 i를 참조하므로, 이 익명 함수는 i를 기억하고 유지할 수 있습니다. 클로저는 같은 함수 내에 정의된 변수를 참조할 수 있는 함수 객체입니다.

func intSeq() func() int {
i := 0 // 함수 내부에서 선언된 i는 지역 변수, 이 함수가 호출될 때마다 새로 초기화됩니다.
// 이 변수는 intSeq의 반환값으로 리턴되는 익명 함수(클로저)에서 참조됩니다.
// 익명 함수란 이름이 없는 함수입니다.
// 반환값: func() int
// 고차 함수란 함수를 매개변수로 받거나, 함수를 반환하는 함수입니다.
return func() int {
i++
return i
}
}

func intSeq() func() int

- 이 선언은 intSeq라는 함수의 정의 입니다.

- intSeq는 클로저를 반환하는 함수입니다.

- intSeq는 반환값으로 함수를 리턴합니다.

고차 함수란 함수를 매개변수로 받거나, 함수를 반환하는 함수입니다.

- 반환하는 함수는 func() int 타입으로, 매개변수를 받지 않고 int 값을 반환합니다.


return func() int { i++; return i }

- intSeq 함수는 익명 함수 func() int { i++; return i } 를 반환합니다. **

- 이 익명 함수는 i 값을 증가시킨 후, 증가된 값을 반환합니다.

  (이 익명 함수는 intSeq 내부에서 선언된 i를 기억합니다.)

  (중요한 점은 익명 함수가 intSeq 함수 내부의 i를 계속 기억한다는 점입니다.)

- 반환된 익명 함수는 i라는 변수를 계속 사용할 수 있는 특별한 함수입니다. 이 특성을 클로저(closure)의 핵심 이라고 합니다.


func main() {
nextInt := intSeq() // 클로저를 반환받아 저장. func() int { i++; return i } 
//intSeq()를 호출하면 i := 0이 생성되고 이를 기억하는 함수가 반환됩니다.
fmt.Println(nextInt()) // 1 nextInt()는 반환된 함수로, 호출할 때마다 i를 1씩 증가시킴
fmt.Println(nextInt()) // 2 nextInt()는 i값 기록있는 func() int { i++; return i }가 실행됨
fmt.Println(nextInt()) // 3 nextInt()는 i값 기록있는 func() int { i++; return i }가 실행됨

// 새로운 클로저 생성- 완전 독립적이며, 로컬변수 i := 0 이 실행됨
anotherInt := intSeq() // anotherInt 는 새로운 클로저로, 별도의 i 값을 유지합니다.
fmt.Println(anotherInt()) // 1 i값 기록있는 func() int { i++; return i }가 실행됨
fmt.Println(anotherInt()) // 2
}

intSeq()를 호출하면 i가 0으로 초기화된 상태로 익명 함수가 반환됩니다.

- nextInt 변수는 이 반환된 익명 함수를 참조합니다.

- nextInt는 i 값을 증가시키는 작업을 수행합니다.

nextInt()를 호출할 때마다 클로저 내부의 i가 증가하고 반환됩니다.

- 첫 번째 호출: i가 0에서 1로 증가 → 1 반환

- 두 번째 호출: i가 1에서 2로 증가 → 2 반환

- 세 번째 호출: i가 2에서 3으로 증가 → 3 반환

새로운 클로저를 생성하면 새로운 i가 초기화됩니다.

새로운 클로저를 생성하면 독립적인 상태를 가지는 새로운 변수를 생성합니다.

- anotherInt := intSeq()는 새로운 i를 생성하며, 값은 0으로 시작합니다.

- 이 클로저는 이전의 nextInt와 독립적으로 작동합니다.


Go 언어에서 클로저는 자신이 참조하는 변수(i)를 메모리에 유지합니다.

이 때문에 intSeq 내부의 i는 nextInt가 존재하는 한 메모리에서 유지되며, 호출 시마다 상태가 업데이트됩니다. (호출때마다 기록값이 있는 함수가(공식이) 작동합는 원리), 변수값에 return 되는 함수를 넣어두고 있는 개념.

---------------------------------------------------------------------------------------

func createAdder(x int) func(int) int {
return func(y int) int {
return x + y
}
}

createAdder 함수: 

- createAdder는 함수를 반환하며, 반환하는 함수는 정수(int)를 매개변수로 받고, 

   정수를 반환합니다.

- 매개변수: x int (정수형 x를 입력받음)

- 반환값: func(int) int


func(y int) int 익명 함수:

- 익명 함수 내부에서 입력받은 y와 외부에서 전달된 x를 더합니다

- return x + y: 클로저(closure)를 이용하여 x 값을 유지합니다


func main() {
add10 := createAdder(10) // x값 + 익명함수 = 변수 add10에 저장해둠
result := add10(5)
fmt.Println(result) // 출력: 15
}

createAdder 호출:

- createAdder(10)을 호출하면, 10을 더하는 함수를 반환합니다.

- 반환된 함수는 add10 변수에 저장됩니다 add10 := createAdder(10)


반환된 함수 호출:

- add10(5)를 호출하면, 반환된 함수의 내부 동작에 따라 10 + 5가 계산됩니다

   result := add10(5)


결과 출력:

- result 변수에 저장된 값을 출력합니다. 결과는 15입니다

- fmt.Println(result) // 출력: 15


package main

import (
"fmt"
)

// 두 수의 합을 계산하는 함수를 반환하는 함수
func createAdder(x int) func(int) int {
return func(y int) int {
return x + y
}
/* 아래와 같이, x값이 10으로 된 상태로, 아래 함수 내용이 add10 변수에 저장되는 원리
변수 호출시, 아래에 x값이 (고정 or 누적)적용된 리턴만 실행되는 원리.
return func(y int) int {
return 10 + y
}
*/
}

func main() {
// 10을 더하는 함수를 생성
add10 := createAdder(10) //add10은 x값 10과 함께 익명함수까지 통째로~ 기억합니다.
// add10을 사용하여 5를 더함
result := add10(5) // 변수에 5를 적용시, 리턴값에 y인자로 들어가, 10+5 =15
fmt.Println(result) // 출력: 15
}

createAdder가 호출되면, 매개변수 x에 값 10이 전달됩니다.

함수 내부에서 익명 함수 func(y int) int { return x + y }를 반환합니다.

반환된 익명 함수는 x = 10이라는 상태를 기억합니다.

간단하게 설명하면: x값 인자로 10을 받으면, x값 10은 계속 유지되고, add10(5)로 y값 5를 받으면,

10 + 5 = 15 가 됩니다.

* 클로저 내부에서 사용되는 변수는 함수가 선언된 환경(scope)에서 캡처된 상태로 저장됩니다.

  클로저에 의해 캡처된 변수는 스택이 아닌 힙에 저장됩니다. 일반 함수는 호출이 끝나면 메모리에서 제거되지만,

  createAdder 함수에서 x는 로컬 변수로 선언되지만, 반환된 익명 함수가 x를 참조합니다

  익명 함수가 x를 참조하는 순간, Go는 x를 힙 메모리에 복사하여 유지합니다.

  이후 반환된 함수는 힙에 저장된 x를 계속 사용할 수 있습니다.

  인자로 받은 x값과 익명함수를 한꺼번에 변수로 기억해두는 원리입니다.

* 힙 메모리에 할당된 클로저 변수는 자동으로 관리됩니다.

  Go의 가비지 컬렉션(GC)이 클로저 변수를 추적하고, 더 이상 참조되지 않는 경우 이를 자동으로 제거합니다.

  직접 힙 메모리에 할당된 변수를 제거할수는 없습니다.(참조하는걸 끊어두면, GO가 자동으로 제거합니다.)

  add10 = nil로 설정하면 클로저 함수에 대한 참조가 사라집니다.

  또는, { } 블록 안에서만 유효하기에, 블록을 벗어나면 참조가 사라져, 클로저는 제거됩니다.

  클로저 변수는, 전역변수로 저장하면 안됩니다. 프로그램이 종료 될때까지, 가비지 컬렉터가 제거하지 못해요.

  클로저를 slice나 map에 저장하면, 자료구조에서 해당 항목을 삭제하지 않는 한 클로저는 유지됩니다.


실행 순서:

createAdder 호출

- createAdder(10)은 익명 함수 func(y int) int { return x + y }를 반환하며, 

  x 값은 10으로 고정됩니다.

- 함수를 변수에 저장

  반환된 함수가 add10 변수에 저장됩니다.

- add10(5) 호출

  호출 시, y 값으로 5를 전달합니다.

  클로저를 통해 x 값(10)은 기억된 상태입니다.

  결과: 10 + 5 = 15

- 결과 출력

  fmt.Println을 통해 결과를 출력합니다.


클로저(Closure)란?

- 클로저는 함수가 외부 환경의 변수를 캡처하여 기억하는 기능입니다.

- createAdder에서 반환된 익명 함수는 x 값을 캡처하여 반환된 후에도 

   계속 사용할 수 있습니다.

   add10 := createAdder(10) // x는 10으로 고정됨

   fmt.Println(add10(5))    // 출력: 15 (x = 10, y = 5)

   fmt.Println(add10(20))   // 출력: 30 (x = 10, y = 20)







20250104

메서드를 검색하고 활용하는 방법 - golnag

 메서드를 검색하고 활용하는 방법 - golnag

- 구글에서 검색

  구글에서 검색할때, docs, documentation, API 같은 키워드와 함께 원하는 검색어 입력해야 정확함.

-Go패키지 웹싸이트에서 검색

- 패키지 웹싸이트의 검색창에서 설명 검색 

- linux 등의 터미널에서 docs 검색 

  [예제] go doc fmt

 - linux 등의 터미널에서 한글변환 docs 한줄씩 검색 방법

translate-shell 로 사용 방법
[설치] sudo apt install python3 python3-pip -y
[설치] sudo apt install translate-shell
[환경설정] export PATH=$PATH:~/.local/bin
[예제] go doc fmt | trans -b :ko


[검색된 메서드의 설명에서 체크할것들]

  입력값: 필요한 매개변수 타입과 의미 확인

  출력값: 반환 타입과 값의 의미 확인

          - 첫번째 반환값, 두번째 반환값.. 등을 확인 

  예제 코드 참고

  설명에 나오는 parameter, return, example 용어 잘 참고

  Parameter (매개변수)

  - Go 언어에서 매개변수는 함수가 호출될 때 전달받는 입력값을 받을 변수입니다.

    함수에 전달되는 입력값을 받는 변수 

    add(a int, b int)에서 a, b는 매개변수

  - 함수 정의 시 괄호 안에 선언되며, 호출할 때 실제 값(인수)이 이 매개변수에 전달됩니다.

  - 매개변수는 타입을 명시해야 합니다.(동일한 타입의 여러 매개변수는 1개로 생략가능)

  - 여러 개의 매개변수를 선언할 수 있으며, 같은 타입일 경우 타입을 생략할 수 있습니다.


  Return (반환값)

  - Go 언어에서 반환값은 함수가 실행 후 결과를 돌려주는 값입니다.

  - return 키워드를 사용하여 값을 반환합니다.함수 실행 결과로 반환되는 값

    참고: return a + b

  - 반환값은 0개, 1개 또는 여러 개일 수 있습니다.

  - 반환값의 타입도 함수 정의 시 명시해야 합니다.

  - 여러 개의 값을 반환할 때는 괄호로 묶습니다.

  - 반환값 이름을 지정하면 더 읽기 쉬운 코드 작성이 가능합니다.

    func square(num int) int {

        return num * num

     } // 에서 int { 괄호앞에 int가 반환값이며, 반환값의 이름 지정하면 알아보기 쉬움.


  Example (예제)

  - 함수 사용법을 보여주는 샘플 코드

  - 예제는 Go 언어의 함수나 기능을 어떻게 사용하는지 보여주는 코드입니다.

  - 일반적으로 문서화, 블로그, 튜토리얼 등에서 제공됩니다.

  - Go는 _test.go 파일을 통해 공식적으로 예제를 작성할 수 있습니다.

  - 예제는 코드의 동작 방식을 이해하기 쉽게 작성됩니다.

  - 표준 라이브러리 문서에서는 예제 코드가 함께 제공됩니다.

  - 테스트 파일 내의 Example 함수로 작성하면, go test로 예제를 실행하며 결과를 확인할 수 있습니다.


Go 언어에서 객체와 메서드 호출의 작동 원리 -golang

Go 언어에서 객체와 메서드 호출의 작동 원리


reader := bufio.NewReader(os.Stdin)

input, err := reader.ReadString('\n')


reader.ReadString('\n') 에서

- reader는 bufio.NewReader로 생성된 객체

- ReadString 은 메서드 라고 하고,  bufio.NewReader(os.Stdin) 객체에서 호출가능한 메서드임.



reader의 정의와 역할

reader := bufio.NewReader(os.Stdin)


bufio.NewReader(os.Stdin):

NewReader는 os.Stdin(표준 입력)에서 데이터를 읽기 위한 bufio.Reader 객체를 생성합니다.

반환된 객체는 *bufio.Reader 타입입니다.


reader:

- reader 변수는 *bufio.Reader 타입객체를 참조합니다.

- 이 객체에는 여러 메서드(ReadString, ReadBytes, ReadRune 등)가 정의되어 있어 호출이 가능합니다.


메서드 호출의 원리: reader.ReadString

객체의 메서드 정의

func (b *Reader) ReadString(delim byte) (string, error)

- ReadString은 bufio.Reader 타입에 정의된 메서드입니다

- (b *Reader)는 수신자(receiver)를 의미합니다.

- b *Reader는 포인터 리시버로 설정된 Reader 타입의 변수입니다.

  리시버: 메서드가 특정 타입에 속하게 만들어주는 역할

- 다른 곳에서 Reader 타입의 변수를 사용하면 .을 통해 ReadString 메서드를 호출할 수 있습니다.

- *Reader 타입의 객체(reader)가 있어야 ReadString 메서드를 호출할 수 있습니다.

- Reader 타입은 Go 표준 라이브러리에서 제공하는 데이터 스트림을 읽는 데 사용되는 타입

  1. 주로 io, bufio, 또는 strings 패키지에서 사용됨.

  2. 파일, 문자열, 네트워크 연결 등 다양한 데이터 소스를 읽을 수 있도록 추상화된 

인터페이스 또는 구조체를 가리킵니다.

  3. Reader 타입은- 구조체 타입(struct type) 또는 인터페이스 타입(interface type)입니다.

  4. Reader는, 기본 타입(int, string)처럼 단순히 값을 저장하는 것이 아니고

데이터를 읽는 동작을 정의하거나 구현한 구조체 또는 인터페이스 타입입니다.


메서드 호출 구문

input, err := reader.ReadString('\n')


reader.ReadString('\n'):

- reader는 *bufio.Reader 타입의 객체입니다.

- reader.ReadString('\n')처럼 메서드를 호출하면, 내부적으로 reader가 b *Reader에 바인딩됩니다.

- reader는 ReadString 메서드의 수신자(receiver) 역할을 합니다.

- ReadString 메서드가 호출되면 reader 객체가 func (b *Reader)에서 b로 전달됩니다.

메서드 호출을 분해하면 다음과 같이 동작합니다:

- reader는 *bufio.Reader 객체입니다.

- ReadString 메서드를 호출할 때 reader가 메서드의 수신자 b전달됩니다.

- ReadString 메서드는 reader의 내부 데이터를 처리해 결과를 반환합니다.


. (dot) 연산자의 역할

- 객체가 가진 메서드나 필드에 접근할 때 사용됩니다.

- 메서드 호출 시 객체는 자동으로 수신자로 전달됩니다.

reader.ReadString에서 . 연산자는 다음과 같은 역할을 합니다:

객체의 메서드 접근:

- reader 객체가 가진 메서드 중 ReadString 메서드를 찾습니다.

- Go 컴파일러는 reader의 타입인 *bufio.Reader를 확인하고, 해당 타입에 정의된 ReadString 메서드를 호출할 수 있음을 알아냅니다.

메서드 호출 시 객체 전달:

bufio.ReadString(reader, '\n')

- reader.ReadString('\n')을 호출하면, 내부적으로 위와 같이 동작합니다

- 즉, reader 객체가 메서드의 첫 번째 매개변수로 암묵적으로 전달됩니다.

변수이름 := bufio.NewReader(os.Stdin) // 변수 이름

input, err := 변수이름.ReadString('\n') // 변수이름 으로 메서드 호출


reader := bufio.NewReader(os.Stdin) // *bufio.Reader 객체 생성

      // bufio.NewReader 함수가 호출되어 새로운 *bufio.Reader 객체를 생성합니다.

      // reader 변수는 이 객체를 참조합니다.

      // reader는 *bufio.Reader 객체입니다.

fmt.Println("Enter text:")


input, err := reader.ReadString('\n') // reader 객체의 ReadString 메서드 호출

      // ReadString 메서드는 *bufio.Reader 타입에 정의된 메서드로, 객체에서 호출 가능합니다.

      // 호출 시 reader 객체가 메서드의 수신자로 전달됩니다.

      // reader 객체에서 ReadString 메서드를 호출합니다.

      // reader는 ReadString 메서드의 수신자로 전달됩니다.

      // delim 매개변수로 '\n'이 전달됩니다.


      // ReadString 메서드는 reader 객체의 내부 버퍼에서 데이터를 읽습니다.

      // 데이터는 '\n'이 나올 때까지 읽으며, 문자열로 반환합니다.

      // 읽은 문자열(input)과 에러(err)를 반환합니다.

if err != nil {

fmt.Println("Error:", err)

return

}


fmt.Println("You entered:", input)




20250101

가스렌지 후드 청소 및 기름때 청소 - 손세정제 + 물티슈

가스렌지 후드 청소 및 기름때 청소시 

 - 손세정제 + 물티슈 = 매우 쉬운 기름때 먼지 청소 효과

가스렌지, 후드, 기타 주방 가전, 스텐레스 등에 찌든 기름때 및 먼지 제거에

손소독제[액체]물티슈에 묻혀서 닦으면, 매우 쉽게 찌든 기름때 먼지가 제거 됩니다.