- Go is a statically typed language with both built in types and user defined types.
- Abstraction methods allowed in go, which allowing you to write code that invokes methods without inplementation.
Types in Go
- Like we define structs, we can also define any other type in go, for example all below declarations are valid in go
type Student struct {
rollno int
name string
marks int
}
type AvgMarks float
type Section string
type Avg func(int)AvgMarks
type ClassAvgMarks func(int, int)AvgMarks
- Types like these can be declared at level with no restrictions but type can be accessed within its scope unless they are expored package block level types.
Abstract Types is one that specifies what a type should do, but not how it is done.
Concrete Type specifies what and how, like implementation of the method.
Methods
- On userdefined types like above, methods can be declared.
- If we define any methods on specified types, then they will have a
receiver
specification between the keyword func and the name of the method. - And here the receiver will have a short name similar to
this
orself
- No method overloading
- We can use same method name for different types.
- Methods must be on the same package level where the respective type has been creted.
Pointer Receivers and Value Receivers
- Go uses parameter of pointer type to indicate that a parameter might be modified by the function.
- Method receivers has same principle
- pointer receivers : type is a pointer
- If any method modifies the receiver, you must use a pointer receiver
- if your method needs to handle nil instances , then a pointer receiver
- value receivers: type is a value
- If your method doesnt modify the receiver, you can use a value receiver.
- pointer receivers : type is a pointer
package main
import (
"fmt"
"time"
)
type Counter struct {
total int
lastUpdated time.Time
}
func (c *Counter) Increment() {
c.total++
c.lastUpdated = time.Now()
}
func (c Counter) String() string {
return fmt.Sprintf("Total %d , lastUpdatedOn %v", c.total, c.lastUpdated)
}
func main() {
var c Counter
fmt.Println(c)
c.Increment()
fmt.Println(c.String())
c.Increment()
fmt.Println(c.String())
}
// Output
/*
Total 0 , lastUpdatedOn 0001-01-01 00:00:00 +0000 UTC
Total 1 , lastUpdatedOn 2009-11-10 23:00:00 +0000 UTC m=+0.000000001
Total 2 , lastUpdatedOn 2009-11-10 23:00:00 +0000 UTC m=+0.000000001
Program exited.
*/
- Similarly, if you pass this type as value to other functions as an argument, then you are not sending its reference, you are making a copy of it and sending, so any changes are limited to that method only. For example
package main
import (
"fmt"
"time"
)
type Counter struct {
total int
lastUpdateOn time.Time
}
func (c *Counter) Increment() {
c.total++
c.lastUpdateOn = time.Now()
}
func (c Counter) String() string {
return fmt.Sprintf("Counter %d , updated On %v", c.total, c.lastUpdateOn)
}
func passByValueChangesLimitToThisFunction(c Counter) {
c.total++
c.lastUpdateOn = time.Now()
fmt.Println("Pass by valuce, changes limited to end of this function", c.String())
}
func passByReferenceChangesAppliedToInstance(c *Counter) {
c.total++
c.lastUpdateOn = time.Now()
fmt.Println("Pass by reference, changes applies to struct instance", c.String())
}
func main() {
var c Counter
fmt.Println(c.String())
passByValueChangesLimitToThisFunction(c)
fmt.Println("After calling pass by value mode, still values stays same", c.String())
passByReferenceChangesAppliedToInstance(&c)
fmt.Println("After calling pass by ref mode, changes applied to instance ", c.String())
}
- Dont write explicit method to fetch/get data from struct instances, unless you need them explicitly.
0 comments:
Post a Comment