본문 바로가기

CS/Go

Go Lang - Package ~ Interface

Package

golang 표준패키지는 golang.org/pkg 참조

 

package를 새로 만드는 것을 기준으로 설명하겠다.

 

package를 공유 라이브러리로 만들 때에는 main패키지나 main 함수를 사용해서는 안된다. go compiler가 그것을 시작점 (entry point)라고 여겨 공유 라이브러리가 아닌 실행 프로그램으로 만들기 때문이다.

main은 제끼고,,, 우리는 programmer이라는 이름의 package를 만들어 보자.

 

먼저 programmer이라는 이름의 폴더를 만들어야 한다.

그리고 이 안에 들어간 파일들 이름은 뭐 여러가지가 있겠지...  그래서 다음과 같은 파일구조를 가진다고 하자.

./programmer

   ㄴ coding.go

   ㄴ caffeine.go

   ㄴ cry.go

 그러면 이 *.go 파일들은 모두 package programmer 밑에 있어야 한다.

 

caffeine.go 파일을 구현해보자.

 

package programmer

import "fmt"

 

먼저 어떤 package에 속한 파일인지를 명시해준다. 우리는 programmer package

다음, 필요한 라이브러리들을 import해준다.

 

Alias

라이브러리를 import 할 때 별명을 붙일 수도 있다. pythong의 import .. as ~ 와 비슷하다. 

import <alias > "library" 처럼 간단하게 해주면 된다.

 

import (
    mongo "other/mongo/db"
    mysql "other/mysql/db"
)
func main() {
    mondb := mongo.Get()
    mydb := mysql.Get()
    //...
}

 

조금 더 나아가서, Alias Declaration이라는 것이 있는데 Specification은 다음과 같다.

identifier => PackageName . identifier 

syntactic issue를 해결하기위해 = 대신 => 을 썼다고 한다.

Some more examples :

 

import "oldp"

var v => oldp.V  // local alias, not exported

// alias declarations may be grouped
type (
	T1 => oldp.T1  // original for T1 is oldp.T1
	T2 => oldp.T2  // original for T2 is oldp.T2
	T3    [8]byte  // regular declaration may be grouped with aliases
)

var V2 T2  // same effect as: var V2 oldp.T2

func myF => oldp.F  // local alias, not exported
func G   => oldp.G

type T => oldp.MuchTooLongATypeName

func f() {
	x := T{}  // same effect as: x := oldp.MuchTooLongATypeName{}
	...
}

Alias에 대한 자세한 설명은 여기 참고

 

Init

package에서 init 은 별도의 호출없이 package가 로드되면서 실행된다.

package를 import하면서 그 안에 다른 건 필요 없고 init()함수만 실행하고 싶어! 하면 import하면서 _ (under bar) 라고 alias를 지정해주면 된다. 

 

func init() {
    caffeines = make(map[string]string)
    caffeines["weak"] = "coffee"
    caffeines["strong"] = "snoopy"
}

 

caffeine.go의 init 함수는 패키지가 로드되면서 caffeines라는 map을 만든다.

 

Scope

으레 library에는 public과 private이 있는 법이다.

Go에서는 이 둘을 굉장히 쉽지만 티 안나게 구분해 놨다.

함수/구조체/인터페이스/메서드 등등... 이름 첫글자가 대문다면 public, 아니면 non-public이다.

따라서, 이름이 소문자로 시작하면 패키지 내부에서만 사용가능하다.

 

흠.. 이게 좋은 건진 잘 모르겠다.

이거 나중에 private에서 public으로 고치면 패키지 내에서 소문자인거 죄다 대문자로 바꿔야 하잖아

글고 나 같은 쪼렙들은 대문자 소문자로 써놓고 어.. 왜 에러나지.. 이러고 있을듯

 

func GetCaffeine (intensity string) string { // 외부에서 호출가능
	return caffeines[intensity]
}

func getAllCaffeines(){ // 내부에서만 호출 가능
	for _, k := range caffeines {
    	fmt.Println(caffeines[k])
    }
}

 

caffeine.go에서 intensity에 해당하는 카페인 가져오는건 public, 모든 caffeine 가져오는 건 non-public이다.

 

 

caffeine.go 의 전문은 요러케 되시겠다! 낄낄.. 조잡해....

 

package programmer

import "fmt"

func init() {
    caffeines = make(map[string]string)
    caffeines["weak"] = "coffee"
    caffeines["strong"] = "snoopy"
}

func GetCaffeine (intensity string) string { // 외부에서 호출가능
	return caffeines[intensity]
}

func getAllCaffeines(){ // 내부에서만 호출 가능
	for _, k := range caffeines {
    	fmt.Println(caffeines[k])
    }
}

 

init함수는 패키지 실행시에 처음으로 호출되는 함수이다.

package가 로드되면 별도의 호출없이 자동으로 실행된다.

 

ㅋㅋㅋㅋㅋㅋ아 힘들어 package 너무 구구절절 설명했더니 너무 길어졌다

 

 

 

 

struct 들어가기 전에 알아야 할 것.

Go에는 Class/ Object/ Inheritancew 개념이 없다

 

 

Struct

다른 OOP들과의 큰 차이점은, Go의 struct는 field만을 가진다는 것이다.

이거 나같은 사람이 코드 잘 못 짜놓으면 협업이 미쳐돌아갈 게 눈에 선하다,,

 

선언은 type 키워드를 이용한다.

 

// struct 정의
type person struct {
    name string
    age  int
}

 

이렇게 선언한 struct로 다양한 방법을 통해 객체를 생성할 수 있다.

struct 필드를 엑세스할 때는 .(dot)을 사용한다. 포인터여도 상관없다.

 

 // person 객체 생성
p0 := person{}
var p1 person
p1 = person{"Jinmyeong", 100}
p2 := person{"Brad Pitt", 25}

// person 객체 포인터 생성
p3 := new(person) 

// 필드값 설정
p0.name = "Gyuri"
p0.age = 22

fmt.Println(p)

 

생성자 (constructor) 함수

struct 리턴하는 함수. 안에 field 들 초기화한다.

아래 코드같은 경우에 data에 map을 초기화해주기 위해 쓴다. 별 다른건 없는 듯..

 

package main
 
type dict struct {
    data map[int]string
}
 
//생성자 함수 정의
func newDict() *dict {
    d := dict{}
    d.data = map[int]string{}
    return &d //포인터 전달
}
 
func main() {
    dic := newDict() // 생성자 호출
    dic.data[1] = "A"
}

 

 

 

 

 

Method

struct가 field만 가지기 때문에 method를 따로 정의해줘야 한다.

그래서 method 정의할 때 이 method가 어떤 struct에 대한 method인지 명시해 주어야 함.

그건 func 키워드 바로 뒤에 parentheses ( () ) 안에다가 써준다.

func (<var name> struct type) <func name>() <ret type> {

}

 

package main
 
//Rect - struct 정의
type Rect struct {
    width, height int
}
 
//Rect의 area() 메소드
func (r Rect) area() int {
    return r.width * r.height   
}

func (r *Rect) area2() int {
	r.width++
    return r.width * r.height
}
 
func main() {
    rect := Rect{10, 20}
    area := rect.area() //메서드 호출
    area2 := rect.area2()
    println(area)
    println(area2)
}

 

위 코드의 (r Rect)처럼 함수명 앞에 타입과 변수명이 붙어 있는 것을 Receiver라고 한다.

요런 reciever가 장착된 함수는 이제 함수가 아니라 메소드가 된다. 키키키~

 

이 Receiver도 value receiver가 있고 pointer receiver가 있다.

pointer receiver는 뭐 생각하는 그대로~ 변수 값을 복사해서 가져오는 게 아니라 주소값을 가져오는 거기 때문에 struct 내의 필드 값이 실제로 변경될 수 있다.

근데 재밌는 건, go에서는 value receiver와 point receiver 사이의 전환을 잘 핸들링 해준다는 것.

pointer var가 아니어도 point receiver를 사용할 수 있다.

 

 

 

 

 

Interface

미쳤냐,, 정리 이거 누가하자 했냐,, 진짜 엄청 많네,.,

 

go에서 인터페이스는 method들의 집합이다. interface 구현하려면 그 안에 있는 method들 다 구현하면 됨.

귀찮아서 그냥 바로 예시 긁어왔슴당

 

//Rect 정의
type Rect struct {
    width, height float64
}
 
//Circle 정의
type Circle struct {
    radius float64
}
 
//Rect 타입에 대한 Shape 인터페이스 구현 
func (r Rect) area() float64 { return r.width * r.height }
func (r Rect) perimeter() float64 {
     return 2 * (r.width + r.height)
}
 
//Circle 타입에 대한 Shape 인터페이스 구현 
func (c Circle) area() float64 { 
    return math.Pi * c.radius * c.radius
}
func (c Circle) perimeter() float64 { 
    return 2 * math.Pi * c.radius

 

 

 

Interface Type

드디어 나왔군! interface type은  빈 interface이며, interface{}와 같이 표현한다.

method를 전혀 갖지 않는데, go의 모든 type은 적어도 0개의 메서드를 구현하므로, 흔히 Go에서 모든 type을 나타내기 위해 빈 interface, 즉 interface type을 사용한다. 다른 언어에서 흔히 일컫는 Dynamic Type (C/C++에서 void*) 라고 할 수 있다.

중요한 말이라 그냥 긁어옴. 

 

놀랍다 크하하,,,

 

 

Type Assertion

 

 

 

 

아 잘 좀 정리해볼라고 요리조리 궁리하다보니 겁나 오래걸린다; 힘들어억

근데 눈에 쏙쏙 들어오는 것 같지도 않음...

 

 

피드백 환영

저 혼자 잘못 알고 있는 게 있다면 제발 알려주셍요ㅜ

 

 

출처 :

http://www.golang.site/

 

예제로 배우는 Go 프로그래밍

쉽고 재미있는 Go 프로그래밍 예제로 배우는 Go 프로그래밍 I like a lot of the design decisions they made in the [Go] language. Basically, I like all of them. - Martin Odersky, Creator of Scala

www.golang.site

https://go.googlesource.com/

 

go Git repositories - Git at Google

 

go.googlesource.com

 

'CS > Go' 카테고리의 다른 글

Go Lang - Function  (700) 2020.05.05
Go Lang - 기초 문법 정리  (238) 2020.05.04