- 구조체 생성
- 구조체와 연결할 메서드를 인터페이스로 정의
- 결과값은 맵에 저장 (맵은 참조형이라 함수에 그대로 넘길 수 있다.)
- 구조체 요소의 개수를 세는 메서드도 구조체로 인터페이스 정의해서 처리할 수 있다?
package main
import (
"fmt"
)
func main() {
e1 := employee{
name: "mike",
age: 31,
salary: 1000,
wage: 0,
emptype: "regular",
}
e2 := employee{
name: "jane",
age: 28,
salary: 500,
wage: 0,
emptype: "contract",
}
e3 := employee{
name: "ralf",
age: 22,
salary: 0,
wage: 100,
emptype: "parttimer",
}
e4 := employee{
name: "danny",
age: 21,
salary: 0,
wage: 110,
emptype: "parttimer",
}
e5 := employee{
name: "sunny",
age: 32,
salary: 0,
wage: 120,
emptype: "parttimer",
}
monthlySalary := map[string]int{
"regular": 0,
"contract": 0,
"parttimer": 0,
}
var empOP empOperation
emps := []employee{e1, e2, e3, e4, e5}
for _, e := range emps {
empOP = e // 가능한 이유는 동일 메서드를 구현했기 때문에 (동일 시그니처)
empOP.setSalary(monthlySalary) // Map은 참조형
}
empOP.getMonthlySalary(monthlySalary)
empOP.getTotal(emps) // 인터페이스 통해 []employee 슬라이스에 접근
}
type empOperation interface {
setSalary(map[string]int)
getMonthlySalary(map[string]int)
getTotal([]employee)
}
type employee struct {
name string
age int
salary int
wage int
emptype string
}
func (e employee) setSalary(m map[string]int) {
switch e.emptype {
case "regular":
m["regular"] += e.salary
case "contract":
m["contract"] += e.salary
case "parttimer":
m["parttimer"] += e.wage
}
}
func (e employee) getMonthlySalary(m map[string]int) {
fmt.Println("monthly regulay salary:", m["regular"])
fmt.Println("monthly contract salary:", m["contract"])
fmt.Println("monthly parttimer salary:", m["parttimer"])
}
func (e employee) getTotal(emps []employee) {
fmt.Println("total person:", len(emps))
}
// 결과
//
// monthly regulay salary: 1000
// monthly contract salary: 500
// monthly parttimer salary: 330
// total person: 5
- 인터페이스로 여러 다른 종류의 변수를 묶어 처리
- 새로운 구조체를 추가하더라도 인터페이스만 구현하면 기존 코드 변경을 최소화할 수 있음
package main
import (
"fmt"
)
func main() {
i := ints{1, 2}
j := floats{1.1, 2.2}
k := ints{3, 4}
cs := []calc{i, j, k}
for _, c := range cs {
show(c)
}
}
type calc interface {
plus()
}
type ints struct {
x, y int
}
func (i ints) plus() {
fmt.Println("int:", i.x+i.y)
}
type floats struct {
x, y float64
}
func (f floats) plus() {
fmt.Println("float:", f.x+f.y)
}
func show(c calc) {
c.plus()
}
// 결과
//
// int: 3
// float: 3.3000000000000003
// int: 7
// 만일 새로운 구조체를 추가할 필요가 있고 인터페이스만 구현했다면
// 아래와 같이 그냥 추가만 하고 기존 코드는 최대한 수정하지 않아도 된다.
package main
import (
"fmt"
)
func main() {
i := ints{1, 2}
j := floats{1.1, 2.2}
k := ints{3, 4}
l := uints{10000, 9999} // 추가
cs := []calc{i, j, k, l} // 추가
for _, c := range cs {
show(c)
}
}
type calc interface {
plus()
}
type ints struct {
x, y int
}
func (i ints) plus() {
fmt.Println("int:", i.x+i.y)
}
type floats struct {
x, y float64
}
func (f floats) plus() {
fmt.Println("float:", f.x+f.y)
}
type uints struct { // 추가
x, y uint64
}
func (u uints) plus() { // 추가
fmt.Println("uint:", u.x+u.y)
}
func show(c calc) {
c.plus()
}
// 결과
//
// int: 3
// float: 3.3000000000000003
// int: 7
// uint: 19999
- 실용적이진 않지만 Go 언어에서 인터페이스를 사용해 만들어 본다.
- 구조체의 멤버를 가지고 개수를 세고, 합치는 결과를 출력한다.
- 구조체를 메서드의 리시버로 받고 count(), merge() 함수에서 int, string으로 리턴한다.
- 인터페이스 슬라이스에 각각을 담고 각각의 객체 (?)에 동일한 이름의 함수를 호출한다.
package main
import (
"fmt"
"strconv"
)
type ints struct {
nums []int
}
func (i ints) count() (count int) {
for i, _ := range i.nums {
count = i
}
count++
return
}
func (i ints) merge() (merge string) {
for _, n := range i.nums {
merge += strconv.Itoa(n)
}
return
}
type strs struct {
txts []string
}
func (s strs) count() (count int) {
for i, _ := range s.txts {
count = i
}
count++
return
}
func (s strs) merge() (merge string) {
for _, t := range s.txts {
merge += t
}
return
}
type operator interface {
count() int
merge() string
}
func main() {
var o operator
o = ints{[]int{1, 2, 3, 4, 5}}
var ops []operator
ops = append(ops, o)
s := strs{[]string{"a", "b", "c"}}
ops = append(ops, s)
for _, op := range ops {
fmt.Printf("%T count: %d\n", op, op.count())
fmt.Printf("%T merge: %s\n", op, op.merge())
}
}
// 결과
//
// main.ints count: 5
// main.ints merge: 12345
// main.strs count: 3
// main.strs merge: abc
package main
import (
"fmt"
)
func main() {
var w Writer = ConsoleWriter{}
w.Write([]byte("Hello World!"))
}
type Writer interface {
Write([]byte) (int, error)
}
type ConsoleWriter struct{}
func (cw ConsoleWriter) Write(data []byte) (int, error) {
n, err := fmt.Println(string(data))
return n, err
}
// 결과
//
// Hello World!
package main
import (
"fmt"
)
func main() {
// int type is defined in another package.
myInt := IntCounter(0)
var inc Incrementer = &myInt
for i := 0; i < 10; i++ {
fmt.Println(inc.Increment())
}
}
type Incrementer interface {
Increment() int
}
type IntCounter int
func (ic *IntCounter) Increment() int {
*ic++
return int(*ic)
}
// 결과
//
// 1
// 2
// 3
// 4
// 5
// 6
// 7
// 8
// 9
// 10
Best Practices
- Use many, small interfaces
* single method interfaces are some of the most powerful and flexible
io.Writer, io.Reader, interface{}
- Don't export interfaces for types that will be consumed
- Do export interfaces for types that will be used by package
- Design functions and methods to receive interfaces whenever possible
댓글 영역