Tour of Go를 기반으로한 Go의 기본 내용입니다.

Methods
기본적으로 Go언어는 클래스를 가지지 않음.
하지만 비슷하게 타입의 메서드를 정의할 수 있다.
메서드는 특별한 receiver인자가 있는 함수인데, func 키워드와 메서드 이름 사이에 위치하고 있다.
package main
import (
"fmt"
"math"
)
type Vertex struct {
X, Y float64
}
//Vertex 구조체 타입에 Abs 메서드
func (v Vertex) Abs() float64 {
//func와 함수명 사이에 리시버가 위치하고있다.
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
v := Vertex{3, 4}
fmt.Println(v.Abs())
}
- 메서드는 리시버 인수가 있는 함수이다!
package main
import (
"fmt"
"math"
)
type MyFloat float64 //구조체가 아닌 타입
func (f MyFloat) Abs() float64 {
if f < 0 {
return float64(-f)
}
return float64(f)
}
func main() {
f := MyFloat(-math.Sqrt2)
fmt.Println(f)
fmt.Println(f.Abs())
}
- 구조체가 아닌 형식에 대해서도 메소드를 선언할 수 있다.
- 메소드와 동일한 패키지에 수신자가 정의되어 있어야 함.
- 타입이 다른 패키지에 정의된 경우(int포함)에는 해당 타입을 리시버로 하여 메서드 정의 불가!
package main
import (
"fmt"
"math"
)
type Vertex struct {
X, Y float64
}
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func (v *Vertex) Scale(f float64) {
v.X = v.X * f
v.Y = v.Y * f
}
func main() {
v := Vertex{3, 4}
v.Scale(10)
fmt.Println(v.Abs())
}
/*
결과
======
50
======
*/
- 포인터 리시버로 메서드를 선언할 수 있음.
- 위 예시에서 만약 Scale 메서드의 리시버를 Vertex로 변경한다면 10배로 scale된 결과를 얻을 수 없었을 것!
package main
import "fmt"
type Vertex struct {
X, Y float64
}
func (v *Vertex) Scale(f float64) {
v.X = v.X * f
v.Y = v.Y * f
}
func ScaleFunc(v *Vertex, f float64) {
v.X = v.X * f
v.Y = v.Y * f
}
func main() {
v := Vertex{3, 4}
v.Scale(2) //편의상 (&v).Scale(2)로 알아서 변환!
ScaleFunc(&v, 10)
p := &Vertex{4, 3}
p.Scale(3)
ScaleFunc(p, 8)
fmt.Println(v, p)
}
/*
결과
======
{60 80} &{96 72}
======
- 위 예시에서 v 문장의 경우, v.Scale(2)는 v가 포인터가 아니더라도 포인터 리시버가 있는 메서드가 자동으로 호출.
- v.Scale(2)를 Go에서 알아서 (&v).Scale(2)로 해석해줌.
- 아래 예시는 그 반대도 가능함을 보여주고 있다.
package main
import (
"fmt"
"math"
)
type Vertex struct {
X, Y float64
}
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func AbsFunc(v Vertex) float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
v := Vertex{3, 4}
fmt.Println(v.Abs())
fmt.Println(AbsFunc(v))
p := &Vertex{4, 3}
fmt.Println(p.Abs()) //(*p).Abs()로 해석
fmt.Println(AbsFunc(*p))
}
- p의 경우, Go에서 (*p).Abs()로 해석해준다.
값 또는 포인터 리시버 선택
- 값 리시버 : 메서드를 통해 호출하는 타입의 값에 대한 수정이 불필요.
- 메서드 리시버 : 메서드를 통해 호출하는 타입의 값 수정이 필요.
일반적으로는 한가지 리시버 형태로 통일하도록 한다. (interface참고)
'Language > Go' 카테고리의 다른 글
[기초] Go 기초 정리 - 5 (Interface) (0) | 2022.07.11 |
---|---|
구조체를 포함하는 구조체 (0) | 2022.07.04 |
[기초] Go 기초 정리 - 3 (Pointer, Struct, Array, Slice, Range, Map, Function value, Function Closure) (0) | 2022.06.26 |
[기초] Slice의 사용과 내부 작동 방식 (0) | 2022.06.23 |
[기초] Go 기초 정리 - 2 (For, If, Switch, Defer) (0) | 2022.06.15 |