{Go} 12. struct / 13. interface
12. struct
- 객체지향적인 추상화를 구조체로 정의한다
- 자바의 클래스와 유사하지만 필드만 있고 매소드는 갖지 않음
=> 리시버를 통해 매소드를 구조체와 연결
기본 사용
// 구조체 선언
type Account struct {
number string
balance float64
interest float64
}
// 구조체에 리시버로 매소드 연결
func (a Account) Calculate() float64 {
return a.balance + (a.balance * a.interest)
}
kim := Account{number: "245-901", balance: 10000000, interest: 0.015}
// 인자 생략 가능
lee := Account{number: "245-902", balance: 20000000}
// 인자 명칭 생략 가능(순서대로 할당해야함)
cho := Account{"245-904", 15000000, 0.4}
// 리시버를 이용해 연결된 매소드 사용
fmt.Println(int(kim.Calculate()))
구조체 포인터 선언
- 구조체 포인터 선언방법 3가지
// 선언 방법1
var kim *Account = new(Account)
kim.number = "245-901"
kim.balance = 1000000000
kim.interest = 0.34
// 선언 방법2
hong := &Account{number: "245-902", balance: 15000000, interest: 0.213}
// 선언 방법3
lee := new(Account)
lee.number = "245-903"
lee.balance = 213434233
lee.interest = 0.213434233
- 리시버인 경우에는 매소드에 선언한 구조체 타입이 포인터형인 경우, 실제 생성 객체가 포인터형이 아니어도 자동으로 주소값을 넘겨주도록 변환이 되는데
type shoppingBasket struct{ cnt, price int }
func (b *shoppingBasket) rePurchaseP(cnt, price int) {
b.cnt += cnt
b.price += price
}
bk := shoppingBasket{3, 5000}
fmt.Println(bk.rePurchaseP(5,1000))
bkPointer := &shoppingBasket{3, 5000}
fmt.Println(bkPointer.rePurchaseP(5,1000))
- 매소드의 입력 인자로 구조체가 들어가는 경우에는 실제 매소드 호출시 넣는 구조체 타입이 반드시 포인터형 이어야함
type shoppingBasket struct{ cnt, price int }
func rePurchaseP(b *shoppingBasket, cnt int, price int) {
b.cnt += cnt
b.price += price
}
//bk := shoppingBasket{3, 5000}
//fmt.Println(rePurchaseP(bk,5,1000)) // bk는 포인터형이 아니므로 불가함
bkPointer := &shoppingBasket{3, 5000}
fmt.Println(rePurchaseP(bk,5,1000))
구조체 익명 선언
// 단건 선언
car1 := struct{ name, color string }{"520d", "red"}
fmt.Println("ex1 : ", car1)
// 구조체 배열 선언
cars := []struct{ name, color string }{{"520d", "red"}, {"530i", "white"}, {"528i", "blue"}}
for _, c := range cars {
fmt.Printf("(%s, %s) --- (%#v) \n", c.name, c.color, c)
}
reflect
import (
"fmt"
"reflect"
)
type Car struct {
name string "차량명"
color string "색상"
company string "제조사"
// 순서 : tag.Field(i).Name tag.Field(i).Type tag.Field(i).Tag
}
tag := reflect.TypeOf(Car{})
for i := 0; i < tag.NumField(); i++ {
fmt.Println(tag.Field(i).Tag, tag.Field(i).Name, tag.Field(i).Type)
}
중첩 구조체
type Car struct {
name string "차량명"
color string "색상"
}
type spec struct { // 첫 글자 소문자 => private 접근제어
length int "전장"
height int "전고"
width int "전축"
}
func main() {
car1 := Car{
"520d",
"silver",
spec{4000, 1000, 2000},
}
13. interface
- 객체의 동작을 표현하고 골격을 잡음
- 추상화 구현
인터페이스 기본
// 동물의 행동을 인터페이스로 선언
type Behaivor interface {
bite()
}
// Dog 구조체
type Dog struct {
name string
weight int
}
// Dog 구조체에 리시버로 bite를 구현
func (d Dog) bite() {
fmt.Println(d.name, "bites!")
}
// [인터페이스 연결 방법 1]
// Dog 객체 생성
dog1 := Dog{"poll", 10}
// 인터페이스 초기화 : Dog에 bite 리시버가 있으므로 할당 가능
var interface1 Behaivor = dog1
// Dog에 리시버로 bite를 구현해 놓았으므로 호출 가능
interface1.bite()
dog1.bite()
// [인터페이스 연결 방법 2]
dog2 := Dog{"marry", 12}
interface2 := Behaivor(dog2)
interface2.bite()
// [인터페이스 연결 방법 3] - 슬라이스
interface3 := []Behaivor{dog1, dog2}
// 인덱스 형태로 실행
for idx, _ := range interface3 {
interface3[idx].bite()
}
// 값 형태로 실행(인터페이스)
for _, val := range interface3 {
val.bite()
}
duck typing : 덕 타이핑
오리처럼 걷고, 소리내고 등 행동을 오리처럼 하면 오리라고 판단할수 있다.
- 구조체 및 변수의 값이나 타입에 상관없이 오로지 구현 매소드로만 판단
type Behaivor interface {
bite()
sounds()
run()
}
func act(animal Behaivor) {
animal.bite()
animal.sounds()
animal.run()
}
// 익명 인터페이스
func actAnonymous(animal interface{ run() }) {
animal.run()
}
// Dog과 Cat 구조체는 각각 bite(), sounds(), run() 리시버를 구현해 놓았음을 가정
dog := Dog{"ppoya", 10}
cat := Cat{"poll", 2}
// 구조체를 넘기지만 함수에서 Behaivor 인터페이스에 대해 다룰 수 있음
// Behaivor 인터페이스 매소드 중 하나라도 구현하지 않았으면 act 매소드의 인자로 전달할 수 없음
act(dog)
act(cat)
// 익명 인터페이스에 전달
actAnonymous(dog)
actAnonymous(cat)
빈 인터페이스 활용
함수 내에서 어떠한 타입이라도 유연하게 매개변수로 받을 수 있음
=> 동적으로 타입이 정해짐
func printValue(s interface{}) {
fmt.Println("ex 1 :", s)
}
dog := Dog{"poll", 10}
cat := Cat{"bob", 5}
printValue(dog)
printValue(cat)
printValue(15)
인터페이스 형변환
인터페이스객체.(타입) 으로 형변환이 가능함
var a interface{} = 15
b := a.(int)
동적으로 입력받은 인터페이스의 타입에 따라 분기 처리에 응용
func checkType(arg interface{}) {
// arg.(type) 을 통해서 현재 데이터형 반환
switch arg.(type) {
case bool:
fmt.Println("this is a bool", arg)
case int, int8, int16, int32, int64:
fmt.Println("this is int", arg)
case float64:
fmt.Println("this is float", arg)
case string:
fmt.Println("this is string", arg)
case nil:
fmt.Println("this is nil", arg)
}
}
checkType(true)
checkType(1)
checkType(22.542)
checkType(nil)
참고자료
[학습 자료] 인프런 - 쉽고 빠르게 끝내는 GO언어 프로그래밍 핵심 기초 입문 과정
[공식사이트] https://golang.org/tutorial
Author And Source
이 문제에 관하여({Go} 12. struct / 13. interface), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@jerry92/Go-12.-struct-13.-interface저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)