2.3 متد (Method)

2.3 متد (Method)

متد در واقع یک تابع گیرنده (reciver) است که به واسطه یک تایپ در دسترس خواهد, تا زمانیکه شما یک متغیر از نوع تایپی که دارای متد می باشد را راه اندازی نکنید به متدهایش دسترسی نخواهید داشت.

اکثرا متد را یکی از عناوین شی گرایی در زبان گو میشناسند که مزایای خوبی دارد بخصوص اگر متدها برای تایپ struct تعریف شوند شما می توانید برای هریک از فیلدهای ساختارتان توابع بخصوصی در قالب متد بنویسید .

در زیر یک نمونه از متد را قرار دادیم :

1func (receiver receiver_type) some_func_name(arguments) return_values

توجه کنید برای تعریف تابع متد باید قبل از اسم تابع پرانتز قرار دهید و داخلش یک نام و تایپ مورد (reciver type) نظر را قرار دهید.

2.3.1 متدها برای ساختار (struct) #

زبان گو یک زبان شی گرا نیست ولی برخی از مفاهیم شی گرایی را بصورت قرار دادی دارد که شما می توانید در کدهای خود استفاده کنید. ساختار در زبان گو یک تایپ می باشد که این تایپ کالکشنی از تایپ های مختلف می باشد که بخش قبلی ما بهش پرداختیم.

در زیر یک مثال در خصوص استفاده از متدها برای ساختار زدیم :

 1package main
 2
 3import "fmt"
 4
 5type employee struct {
 6    name   string
 7    age    int
 8    salary int
 9}
10
11func (e employee) details() {
12    fmt.Printf("Name: %s\n", e.name)
13    fmt.Printf("Age: %d\n", e.age)
14}
15
16func (e employee) getSalary() int {
17    return e.salary
18}
19
20func main() {
21    emp := employee{name: "Sam", age: 31, salary: 2000}
22    emp.details()
23    fmt.Printf("Salary %d\n", emp.getSalary())
24}
1$ go run main.go
2Name: Sam
3Age: 31
4Salary 2000

در کد بالا ما یک ساختار با نام employee ایجاد کردیم و سپس برایش ۲ تا متد با نام های details و getSalary تعریف کردیم. حال برای اینکه بتوانیم از این متدها استفاده کنیم داخل تابع main ما یک متغیر از نوع employee تعریف کردیم و سپس با استفاده از نقطه . پس از نام متغیر به متدها دسترسی پیدا کردیم همانند دسترسی به فیلدهای ساختار.

آیا با استفاده از متد می توانیم مقدار یکی از فیلدهای داخل ساختار را تغییر دهیم ؟ این سوال ۲ جواب دارد هم آره و هم خیر

حال به مثال زیر توجه کنید تا توضیح دهیم :

 1package main
 2
 3import "fmt"
 4
 5type employee struct {
 6    name   string
 7    age    int
 8    salary int
 9}
10
11func (e employee) setNewName(newName string) {
12    e.name = newName
13}
14
15func main() {
16    emp := employee{name: "Sam", age: 31, salary: 2000}
17    emp.setNewName("John")
18    fmt.Printf("Name: %s\n", emp.name)
19}
1$ go run main.go
2Name: Sam
  • علت اینکه می گوییم خیر : به خاطر اینکه ما داریم با یک کپی از فیلدهای ساختار کار می کنیم و با تغییر مقدار هر یک از فیلدها تغییر صورت نمی پذیرد.
  • اما علت اینکه می گوییم آره : اگر ما با استفاده از اشاره گر به فیلدهای داخل ساختار دسترسی پیدا کنیم می توانید مستقیما داخل خانه حافظه مشخص شده مقدار فیلد مورد نظر ساختار را در هرجایی از پروژه تغییر دهیم.

2.3.2 استفاده از اشاره گر (pointer) در متدها #

در بالا ما مثالی زدیم و اشاره کردیم به اینکه آیا می توانید مقدار هر یک از فیلدهای ساختار را با استفاده از متد تغییر دهیم یا خیر و در پاسخ گفتیم آره و خیر و علت آره را توضیح دادیم. حال می خواهیم با یک مثال این مورد را توضیح دهیم.

 1package main
 2
 3import "fmt"
 4
 5type employee struct {
 6    name   string
 7    age    int
 8    salary int
 9}
10
11func (e *employee) setNewName(newName string) {
12    e.name = newName
13}
14
15func main() {
16    emp := &employee{name: "Sam", age: 31, salary: 2000}
17    emp.setNewName("John")
18    fmt.Printf("Name: %s\n", emp.name)
19}
1$ go run main.go
2Name: John

در بالا متد setNewName یک نوع متد گیرنده از نوع اشاره گر است که ما داخل این تابع متد به مقدار فیلدهای داخل خانه حافظه ساختار employee دسترسی داریم و می توانیم مقدار دهی کنیم.

آیا استفاده از گیرنده اشاره گر واقعا ضروری است؟ خیر, ضروری نیست زیرا ما وقتی به متدها دسترسی داریم که یک نمونه (instance) از تایپ مورد نظر ایجاد کنیم تا به متدهایش دسترسی داشته باشیم و همچنین اگر فرضا نیاز داشته باشیم که یکی از فیلد های ساختار را مقدار دهی کنیم بازم می توانیم به آدرس خانه متغیری که ساختار راه نگه داری می کند اشاره کنیم و مقدارش را تغییر دهیم.

 1package main
 2
 3import "fmt"
 4
 5type employee struct {
 6    name   string
 7    age    int
 8    salary int
 9}
10
11func (e *employee) setNewName(newName string) {
12    e.name = newName
13}
14
15func main() {
16    emp := employee{name: "Sam", age: 31, salary: 2000}
17    emp.setNewName("John")
18
19    fmt.Printf("Name: %s\n", emp.name)
20
21    (&emp).setNewName("Mike")
22    fmt.Printf("Name: %s\n", emp.name)
23}
1$ go run main.go
2Name: John
3Name: Mike

2.3.2.1 چه موقع باید از گیرنده اشاره گر برای متد استفاده کنیم #

  • زمانیکه قصد داریم متدهایی بنویسیم که برروی مقدار فیلدهای ساختار در زمان اجرا تغییراتی انجام دهد.
  • زمانیکه ساختار خیلی بزرگ است و کلی فیلد دارد در اینجا بهتر از گیرنده اشاره گر استفاده کنیم تا هر بار با یکی کپی از ساختار مواجه نشویم و اینکار سربار را کم می کند.

2.3.4 تعریف متد برای فیلدهای ساختار تو در تو (nested) #

شما می توانید برای فیلدهایی که ساختار تو در تو دارد متد بنویسید :

 1package main
 2
 3import "fmt"
 4
 5type employee struct {
 6	name    string
 7	age     int
 8	salary  int
 9	address address
10}
11
12type address struct {
13	city    string
14	country string
15}
16
17func (a address) details() {
18	fmt.Printf("City: %s\n", a.city)
19	fmt.Printf("Country: %s\n", a.country)
20}
21
22func main() {
23	address := address{city: "London", country: "UK"}
24
25	emp := employee{name: "Sam", age: 31, salary: 2000, address: address}
26
27	emp.address.details()
28}
1$ go run main.go
2City: London
3Country: UK

در بالا ما یک متد برای ساختار address تعریف کردیم و سپس ساختار address را داخل ساختار employee گذاشتیم. در نهایت شما با استفاده از employee می توانید به متدهای address هم دسترسی داشته باشید و استفاده کنید.

comments powered by Disqus