GO 모듈 내에서, Receiver 를 pointer 로 받는 형태로 함수를 정의한다는건
해당 struct 의 상태를 관리하겠다는 것과 같다.
package module_a
type Config struct{
width *Widget.Width
height *Widget.Height
}
func(cf *Config) initSize() {
cf.width = Widget.Width(200)
cf.height = Widget.Height(150)
}
cf.initSize()
따라서 해당 패키지 내의 struct 를 다른 모듈에서 Receiver 로 받는것을 막아놨다.
package module_b
// 설령 Config 로 public 하게 열어놨어도
// Receiver 로 직접 상태를 관리할 수 없다.
(cf *module_a.Config) func modifySize() {
}
상태 변경을 원한다면 Receiver 가 아니라, 인자로 받아야한다.
package module_b
func modifyWidgetSize(cf *module_a.Config) {
// Do something
}
눈치 챘는가? Receiver 를 받아 정의하는 순간, 상태를 관리하게 되고
이는 java 와 tyepscript의 class 와 유사하게 '함수' 가 아닌 특정 인스턴스에 귀속된 '메소드'가 된다.
즉, Receiver 로 정의하는 순간 함수가 아닌 '메소드'가 된다.
package module_b
// Error: Unresolved type 'module_a'
func(cf *module_b.Config) modifySize(){
}
사실 조금만 생각해보면 당연하다.
java는 class 정의시 한 파일 내에서 처음부터 끝가지 구성한다.
헌데, go에서 다른 패키지에서 해당 instance 의 상태를 변경할 메소드를 직접 정의한다는 것 자체가 어색하다.
java 에서 한 클래스 내의 메소드가 여러 패키지, 여러 파일로 찢어져있다고 상상해보라. 아찔하지 않나?
사실 인자로 받아와도 마찬가지다.
패키지가 같다면 설령 첫 글자를 소문자로 정의한 struct라 하더라도 Receiver 를 통한 메소드 정의가 가능하다. 이는 node.js 와 달리 go 에서는 메소드나 함수 범위 바깥에 (아래 예제에선 config
struct) 정의된 경우, package scope 내에서 즉, 동일 패키지 내의 다른 파일에서 자유롭게 접근이 가능하다.
따라서 java에서 메소드를 public
으로 지정했던 것처럼 메소드를 정의하고 싶다면 당연 첫 글자는 대문자로 적어야한다.
package module_a
type config struct {
widget int64
height int64
}
var Config config
// 첫 글자가 대문자므로 다른 package 에서도 메소드 사용 가능.
// 이때, module_a.Config.InitSize() 이런 식으로 호출하게됨.
func (cf *config) InitSize() {
cf.height = 40
}
package module_a
// 동일 패키지 내에서는 다른 파일이어도 메소드 추가 정의 가능.
func (cf *config) reSize(height int64) {
cf.height = height
}