본문 바로가기
Programming/GO

Effective Go에 대해 - 3

by 코인선물로부자된다 2023. 1. 2.
반응형

Methods

Pointers VS Values

어떠한 변수, 어떠한 버퍼등 할당 받아서 사용하는데, 모든 변수의 주소를 저장하거나 사용하기 위한 변수가 포인터이므로, 간결하고 효율적인 표현과 처리를 위해 사용

포인터 변수의 경우, 주소를 직접적으로 컨트롤 하므로, 예외 처리를 확실하게 해줘야한다.
Go 언어는 객체지향 프로그래밍을 고유의 방식으로 지원하므로 Struct가 필드만을 가지고, 메서드는 별도로 분리되어 정의된다.

Go Method는 특별한 형태의 func 함수a

package main

//Rect - struct 정의
type Rect struct {
    width, height int
}

//Rect의 area() 메소드
func (r Rect) area() int {
    return r.width * r.height   
}

func main() {
    rect := Rect{10, 20}
    area := rect.area() //메서드 호출
    println(area)
}

Interfaces and other types

Interfaces

객체의 행위를 지정해 주는 하나의 방법
어떤 객체가 정해진 행동을 할 수 있다면 호환되는 타입으로 사용할 수 있다.
구조체(Struct)가 필드의 집합체라면, interface는 method의 집합체

type Shape interface {
    area() float64
    perimeter() float64
}

//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
}

Conversions

새로운 값을 쓰지 않고, 지금 값에 새로운 타입이 있는 것처럼 쓰는 방법.. 예를 들어 sort를 위해 여러 인터페이스를 구현하지 않고 타입을 변환시켜서 진행

func (s Sequence) String() string {
    s = s.Copy()
    sort.Sort(s)
    return fmt.Sprint([]int(s))
}

Interface Conversions and Type Assertions

빈인터페이스가 존재한다. (어떤 타입도 담을 수 있는 컨테이너, Dynamic Type)
Empty Interface는 메서드를 전혀 갖지 않는 빈 인터페이스로 흔히 Go에서 모든 Type을 나타내기 위해 빈 인터페이스를 사용한다.

func A(a  ...interface{}) (n int, err error)

Interface type의 x와 타입 T에 대하여 x.(T)로 표현했을 때, 이는 x가 nil이 아니며, x는 T 타입에 속한다는 점을 확인하고자 하는 표현등을 Type Assertion이라 부른다.

func main() {
    var a interface{} = 1

    i := a       // a와 i 는 dynamic type, 값은 1
    j := a.(int) // j는 int 타입, 값은 1

    println(i)  // 포인터주소 출력
    println(j)  // 1 출력
}

 

The blank identifier

  • 어떤 형태의 값도 받을 수 있음
  • noise를 관리하기위한 수단
  • 실제로 어떤 변수에 값을 할당하고 사용하지않으면 경고메세지가 뜸

Unused imports and variables

package main
import _ "net/http/pprof" . - side effect를 위한 호출- 호출을 통한 초기화(debugging 용도)
import (
    "fmt"
    "io"
    "log"
    "os"
)

var _ = fmt.Printf // For debugging; delete when done.
var _ io.Reader    // For debugging; delete when done.

func main() {
    fd, err := os.Open("test.go")
    if err != nil {
        log.Fatal(err)
    }
    // TODO: use fd.
    _ = fd
}

embedding

  • subclassing 상속, 기능을 이전하는것/ 반복된 코드를 줄이기위해서 method의 재사용은 꼭필요하고, 그것을 embedding을 통해서 구현하고있다.
type Reader interface { 
    Read(p []byte) (n int, err error) 
} 

type Writer interface { 
    Write(p []byte) (n int, err error) 
}

type ReadWriter interface {
    Reader
    Writer
}
  • readwriter는 reader와 writer의 매소드를 둘다 사용가능하다.
  • 인터페이스 embedding은 인터페이스로만 가능하다
  • struct의 embedding은 더 광범위하게 사용가능
type ReadWriter struct {
    *Reader  // *bufio.Reader
    *Writer  // *bufio.Writer
}
type ReadWriter struct {
    reader *Reader
    writer *Writer
}
  • 두가지는 실제로 하위 method를 호출할때 호출방식의 차이가 생긴다