Programming/Go lang

[go lang] ์ธํ„ฐํŽ˜์ด์Šค

jison 2024. 7. 13. 12:48

์ธํ„ฐํŽ˜์ด์Šค ์ •์˜, ๊ตฌํ˜„

์ธํ„ฐํŽ˜์ด์Šค๋Š” ๋ฉ”์†Œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜์˜ ์ง‘ํ•ฉ์œผ๋กœ, ์–ด๋–ค ํƒ€์ž…์ด ํŠน์ • ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ธํ„ฐํŽ˜์ด์Šค์— ๋ช…์‹œ๋œ ๋ฉ”์†Œ๋“œ๋ฅผ ๋ชจ๋‘ ๊ตฌํ˜„ํ•˜๋ฉด ๋œ๋‹ค. ์•„๋ž˜๋Š” DBManager ๋ผ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ •์˜ํ•˜๊ณ  *MySQLDBManager ํƒ€์ž…์ด ์ด๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ์˜ˆ์ œ์ด๋‹ค.

// ์ธํ„ฐํŽ˜์ด์Šค ์ •์˜
type DBManager interface {
    Connect(ip string, user string, pw string) bool
    Query(q string) Data
    Commit() bool
    Disconnect() bool
}

// Concrete Type ์ •์˜
type MySQLDBManager struct {
    ...
}

// MySQLDBManager์˜ DBManager ๊ตฌํ˜„
func (m *MySQLDBManager) Connect(ip string, user string, pw string) bool {
    ...
}

func (m *MySQLDBManager) Query(q string) Data {
    ...
}

func (m *MySQLDBManager) Commit() bool {
    ...
}

func (m *MySQLDBManager) Disconnect() bool {
    ...
}

์ด๋ฅผ ์ด์šฉํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํด๋ผ์ด์–ธํŠธ ๊ตฌํ˜„์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

var m DBManager

// MySQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋งค๋‹ˆ์ € ๊ตฌํ˜„ ์ด์šฉ
m = MySQLDBManager{}
m.connect(...)
...

// Oracle ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋งค๋‹ˆ์ € ๊ตฌํ˜„ ์ด์šฉ
m = OracleDBManager{}
m.connect(...)
...

Type Assertions, Type Switch

๋นˆ ์ธํ„ฐํŽ˜์ด์Šค(empty interface; interface{}) ๋ณ€์ˆ˜์˜ ๊ฒฝ์šฐ ๋ชจ๋“  ํƒ€์ž…์˜ ๊ฐ’์„ ๋‹ด์„ ์ˆ˜ ์žˆ๋‹ค.(์™œ๋ƒํ•˜๋ฉด ๋ชจ๋“  ํƒ€์ž…์€ ์ ์–ด๋„ 0๊ฐœ ์ด์ƒ์˜ ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๋ฏ€๋กœ) Type Assertion(ํƒ€์ž… ๋‹จ์–ธ)์„ ํ†ตํ•ด ์ธํ„ฐํŽ˜์ด์Šค ๋ณ€์ˆ˜์— ๋‹ด๊ธด ๊ฐ’์„ ํŠน์ • ํƒ€์ž…์œผ๋กœ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋‹ค. ์•„๋ž˜ ์˜ˆ์ œ ์ฝ”๋“œ๋Š” s = i.(string) ๋˜๋Š” s, ok = i.(string) ๋กœ ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๋Š”๋ฐ, ์ฒซ ๋ฒˆ์งธ ๋ฌธ๋ฒ•์˜ ๊ฒฝ์šฐ ๊ฐ’์„ ๋‹จ์–ธํ•œ ํƒ€์ž…์œผ๋กœ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†๋‹ค๋ฉด ๋Ÿฐํƒ€์ž„ ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค. ๋‘ ๋ฒˆ์งธ ๋ฌธ๋ฒ•์˜ ๊ฒฝ์šฐ ๋‹จ์–ธํ•œ ํƒ€์ž…์œผ๋กœ ๊ฐ’์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค๋ฉด ๊ฐ’๊ณผ true๋ฅผ, ๊ทธ๋Ÿด ์ˆ˜ ์—†๋‹ค๋ฉด ๋‹จ์–ธํ•œ ํƒ€์ž…์˜ zero-value์™€ false๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

var i interface{}

i = "Hello world"

s = i.(string)
s, ok = i.(string) // "Hello world", true

f, ok = i.(float64) // 0.0, false

switch ๋ฌธ์—์„œ ํƒ€์ž… ๋‹จ์–ธ ์ด์šฉ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

switch v := i.(type) {
case int:
    ...
case string:
    ...
default:
    ...
}

์˜ˆ์ œ: Error ๊ตฌํ˜„

type error interface {
    Error() string
}

'๊ฐ„๋‹จํ•œ' ์ œ๊ณฑ๊ทผ ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜์— ์—๋Ÿฌ ๋ฐ˜ํ™˜์„ ์ถ”๊ฐ€ํ•˜์ž. Error ์ธํ„ฐํŽ˜์ด์Šค๋Š” ์œ„์™€ ๊ฐ™์ด ์ •์˜๋˜์—ˆ๋‹ค.

type ErrNegativeSqrt float64

func (e ErrNegativeSqrt) Error() string {
    return fmt.Sprintf("cannot Sqrt negative number: %v", float64(e))
}

func Sqrt(x float64) (float64, error) {
    if x < 0.0 {
        return 0.0, ErrNegativeSqrt(x)
    }
    z := 1.0
    for i := 0; i < 10; i++ {
        z -= (z*z - x) / (2 * x)
    }
    return z, nil
}

์˜ˆ์ œ: rot13 ์•”ํ˜ธํ™” ๋ฐ”์ดํŠธ ์ŠคํŠธ๋ฆผ ๊ตฌํ˜„

type Reader {
    func Read(b []byte) (n int, err error)
}

Reader ์ธํ„ฐํŽ˜์ด์Šค๋Š” ์œ„์™€ ๊ฐ™์ด ์ •์˜๋˜์—ˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด b []byte ์— ๊ธฐ๋กํ•˜๊ณ  ์ฝ์€ ๋ฐ”์ดํŠธ์ˆ˜ n์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๋งŒ์•ฝ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค๋ฉด error๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , ์—๋Ÿฌ๊ฐ€ ์—†๋‹ค๋ฉด nil ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

type Rot13Reader struct {
    r io.Reader
}

func rot(b byte) byte {
    switch {
    case 'a' <= b && b <= 'z':
        return (b - 'a' + 13) % 26 + 'a'
    case 'A' <= b && b <= 'Z':
        return (b - 'A' + 13) % 26 + 'A'
    default:
        return b
    }
}

func (r Rot13Reader) Read(buffer []byte) (int, error) {
    n, err := r.r.Read(buffer)
    if err != nil {
        return n, err
    }
    for i := range n {
        buffer[i] = rot(buffer[i])
    }
    return n, nil
}