TIL 07 - Class: 객체지향과 Json(Golang)

프동프동·2023년 2월 10일
0

TIL

목록 보기
7/46
post-thumbnail

Class: 객체지향

일반적인 객체지향 언어인 JAVA, C++등과 달리 class, inheritance 등을 지원하지 않는다. 하지만 sturct를 활용하여 객체를 구현하고, channel을 통해 객체 간 통신(상호 작용)하며 embedding을 통해 컴포지션이 가능하다는 점에서 충분히 객체지향적이라고 할 수 있다.

  • 특징
    • 객체지향 스타일은 허용하지만 수직적 상속 계층이 없음
    • class 구현은 struct를 사용하여 구현
    • 구조체와 메서드 연결을 통해 타 언어의 클래스 형식처럼 사용가능
  • 사용 방법
    • 다양한 선언 방법 1
      type Account struct {
      	number   string
      	balance  float64
      	interest float64
      }
      
      var kim *Account = new(Account)
      kim.number = "245-901"
      kim.balance = 10000000
      kim.interest = 0.015
    • 다양한 선언 방법 2
      
      type Account struct {
      	number   string
      	balance  float64
      	interest float64
      }
      
      hong := &Account{number: "245-902", balance: 15000000, interest: 0.04}
    • 다양한 선언 방법 3
      type Account struct {
      	number   string
      	balance  float64
      	interest float64
      }
      
      lee := new(Account)
      lee.number = "245-903"
      lee.balance = 13000000
      lee.interest = 0.025
  • 구조체 익명 선언 및 활용
    // 익명 선언 
    car := struct{name, color string}{"520d", "black"}
    // 익명 구조체 리스트
    cars := []struct{name, color string}{{"520d","black"},{"530i", "red"}}}
    for _, c := range cars {
    		fmt.Printf("(%s,%s) ----- (%#v)\n", c.name, c.color, c)
    }
    

Value와 Pointer의 차이

함수는 기본적으로 Value 호출

변수의 값이 복사 후 내부에 전달된다

맵, 슬라이스 등은 참조 값(주소)으로 전달한다.

  • Value 리시버
    • 객체의 복사본을 만들어 함수에 전달한다.

    • Value 리시버로 전달받은 값은 변경하여도 원래 값은 수정되지 않는다.

      type shoppingBasket struct{ cnt, price int }
      
      // 결제 함수
      func (b shoppingBasket) purchase() int {
      	return b.cnt * b.price
      }
      
      // 원본 수정x (값 전달 형식)
      func (b shoppingBasket) rePurchaseD(cnt, price int) {
      	b.cnt += cnt
      	b.price += price
      }
  • Pointer 리시버
    • 객체의 주소를 함수에 전달한다

    • 객체의 메모리 위치에 대해 참조(그 자체를 전달)하기 때문에 함수 안에서 수행된 변경 사항에 대해서 원래 객체가 변경된다.

      // 원본 수정(참조 형식)
      func (b *shoppingBasket) rePurchaseP(cnt, price int) {
      	b.cnt += cnt
      	b.price += price
      }

임베딩(Embedding)

  • Embedding 방식을 통해 상속을 대신하며 컴포지션(Composition)방식으로 클래스 관계를 구성할 수 있다.
  • 사용 방법
    • 구조체.함수명()

      type Car struct {
      	name string
      	color string
      	price int64
      	tax int64
      }
      
      // 일반 메서드
      func Price(c Car) int64 {
      	return c.price + c.tax
      }
      // 구조체 <-> 메서드 바인딩
      func (c Car) Price() int64{
      	return c.price + c.tax
      }
      
      bmw := Car{name:"520d", price:500000000, color: "white", tax: 50000000}
      benz := Car{name:"220d", price:600000000, color: "white", tax: 60000000}
      
      fmt.Println("ex : ", bmw.Price())
      fmt.Println("ex : ", benz.Price())

JSON

“encoding/json” 패키지에서 제공

  • 특징
    • 구조체로 타입을 정의할 때 태그를 이용하면 프로퍼티명을 변경할 수 있다.

      type User struct {
      	Name string `json:"name"`
      	Age int     `json:"age"`
      }

Marshal

JSON 문자열([]byte 형)로 변환

  • 함수
    func Marshal(v interface{}) ([]byte, error)
  • 사용 방법
    • data, err := json.Marshal(value)

      func main() {
      	data, _ := json.Marshal(true)
      	fmt.Println(data)
      	fmt.Println(string(data))
      }
    • boolean Type인 true를 받아 [116 114 117 101]라는 바이트 슬라이스를 반환한다.

    • 이를 string() 함수를 통해 문자열로 변경하면 true를 얻을 수 있다.

Unmarshal

JSON 문자열을 받아 자료구조로 변환

  • 함수
    func Unmarshal(data []byte, v interface{}) error
    • v의 타입에 따라 언마샬링한다.
  • 사용 방법
    • err := Person.Unmarshal(data, &value)

      func main() {
      	var temp bool
      	json.Unmarshal([]byte("true"), &temp)
      	fmt.Printf("%t\n", temp) // %t는 Boolean
      }
    • 첫번째 인자값으로 바이트 슬라이스를 넘겨준다.

    • 두번째 인자값으로 결과를 담게될 변수 포인터를 넘겨준다.

Encoder/Decoder

메모리에 임시 저장된 데이터를 반환하지 않고, 스트림(파일, 네트워크 소켓등 데이터 입출력 장치)에 직렬화된 데이터를 쓰는데 사용한다.

Encoder

type Encoder struct
func NewEncoder(w io.Writer) *Encoder
func (enc *Encoder) Encode(v interface{}) error
  • 사용 방법
    1. json.NewEncoder로 인코더 생성

      • 첫번째 인자값으로 io.Writer 타입을 받는 값을 넣는다.(출력 할 곳)
    2. json.Encode 함수로 JSON으로 변환
      - 첫번째 인자값으로 NewEncoder로 설정한 출력 값으로 User 값을 보내 인코딩된 JSON문자열을 출력시킨다.

      func main() {
      	u := User{"FDongFDong", 30}
      	// os.Stdout : 표준 출력
      	enc := json.NewEncoder(os.Stdout)
      	enc.Encode(u)
      }

Decoder

인코딩과 반대로 JSON 문자열을 값으로 바꾸는 기능

type Decoder struct
func NewDecoder(r io.Reader) *Decoder
func (dec *Decoder) Decode(v interface{}) error
  • 사용 방법
    1. json.NewDecoder로 디코더 생성
      • 첫번째 인자값으로 io.Reader 타입을 받는 값을 넣는다.(입력 받을 곳)
    2. json.Decode로 JSON 문자열을 값으로 변경한다.
      • 첫번째 인자값으로 NewDecoder에서 설정한 표준 입력으로 값을 받는다.
    • 생성된 디코더는 표준 입력으로 연결된 스트림을 갖게된다.

      type User struct {
      	Name string `json:"name"`
      	Age  int    `json:"age"`
      }
      
      func main() {
      	var u User
      	dec := json.NewDecoder(os.Stdin)
      	dec.Decode(&u)
      	fmt.Printf("%+v\n", u)
      }
    • 표준 입력으로부터 데이터가 들어오면 Decode(&u) 메서드에 의해 User 데이터로 변경된다.

마샬링과 인코딩의 차이

  • Marshal/Unmarshal
    • 바이트 슬라이스, 문자열 이용시 적합
  • Encoder/Decoder
    • 표준 입출력, 파일과 같은 io.Reader/Writer 인터페이스를 사용하여 스트림기반으로 동작시 적합
  • 속도
    • 스트림 기반의 Encoder/Decoder가 더 빠르다.
profile
좋은 개발자가 되고싶은

0개의 댓글