As we have explored major Data Structures in Part I of the Fifth Chapter, let’s dive deeper into Part II –
JSON(JavaScript Object Notation) is a simple text-based data interchanging format. Basically, we use structs for JSON for putting and receiving the data. It is lightweight and gives faster performance for accessing the data
Go has built-in support for JSON encoding by providing functions in “json/encoding” package.
Marshalling converts the Golang object to JSON encoding into strings. Golang has provided marshal( ) function for this –
func Marshal( v interface { }) ([ ]byte,error)
This function will convert the given data structure into JSON in [ ]byte format which we need to convert into a string.
Example – Given data structure Person
type Person struct{ Name string Address string age int /* this field will not be converted into JSON as should start with capital letter */ }
Create an instance of Person
per:=Person{“George”,”United Kingdom”,25}
Now, we can marshal encoded JSON using marshal( ) function. But don’t forget to import the “encoding/json” package.
B,err := json.Marshal(per)
If marshalling happens, then err will be nil and b will be [ ] byte containing JSON data like below.
b==[ ]byte {`{“Name”:”George”,”Address”:”United Kingdom”}`}
Here, as per the above struct age field will not come because it is not exported which is mandatory for all fields.
Now, we need to convert this [ ]byte to string. So do the typecasting
string(b)
Now, JSON will be like {“Name”:”George”,”Address”:”United Kingdom”}
Points:
Unmarshalling converts the JSON data to GO objects. Golang has provided unmarshal( ) function for this –
func Unmarshal(data [ ]byte,v interface{ })
Here, we specify JSON text as a string and convert into [ ]byte slice
Now, first, create the place of that struct type where decoded data will be stored.
var per Person
Now call json.Unmarshal( ) by passing it a []byte of JSON data and a pointer to per.
err:=json.Unmarshal(b,&per)
If the JSON fits and matches with struct fields, after the call err will be nil and data from b will have been stored in the struct m, but non-matched fields will not be decoded
String keys in JSON must be matched to struct fields.
The tags are given to the fields to attach meta information and acquired by using reflection. It is used to provide info on how struct field is encoded to or decoded from another format (or stored /retrieved from the database), but you can use it to store whatever meta-info you want either for another package or for your use.
As we see in the documentation of reflect. StructTag, by convention the value of a tag string is a space-separated key:“value” pairs.
Example –
type User struct{ Name string ` json:”name” xml:”name” ` //tag in backticks }
If you want to send some field value empty then write “omitempty” flag in order to let JSON parser know.
type User struct{ Name string ` json:”name” xml:”name” ` Age int `json:”omitempty”` }
With omitempty JSON value will be { }
We can use reflection(reflect package) to access the tag values of struct fields. We need to acquire the type of struct and then we can give query to fields e.g. Type.Field(i int) / Type.FieldbyName(name string)
This will return value of struct field.
The commonly used tag keys are →
package main import ( "encoding/json" "fmt" ) type person struct { Firstname string Lastname string Age int `json:"Umar"` //tag in backticks notexported int //will not be exported } func main() { p1 := person{"Rob", "Pike", 24, 007} bs1, _ := json.Marshal(p1) // Marshalling fmt.Println(string(bs1)) bs := []byte(bs1) json.Unmarshal(bs, p1) //Unmarshalling fmt.Println(bs) }
Encoding works with writer and writing streams of JSON data. The GO has provided below function for encoding JSON through writer interface –
func (enc *Encoder) Encode (v interface{ }) error
json.NewEncoder(os.Stdout).Encode(p1)
If we see the source code, the NewEncoder(w *io.Writer) *Encoder takes writer and returns a pointer to an Encoder for encoding and os. Stdout is open files pointing to standard input. Stdout is a pointer to file and a pointer to a file implements func(f *file ) Write(b [ ]byte) (n int,err error) and that means it is implementing this method from Writer interface. (Polymorphism)
main.go package main import ( "encoding/json" "fmt" "os" ) type person struct { Name string Age int } func main() { p1 := person{"George", 23} json.NewEncoder(os.Stdout).Encode(p1) /* Encoding through Streams */ fmt.Println(p1.Name, "--", p1.Age) }
Decoding works with reader and reading streams of JSON data. The GO has provided below function for encoding JSON through writer interface –
func (dec *Decoder) Decode (v interface{ }) error
NewReader( ) will return a reader and give it to NewDecoder( ) so that it will decode the JSON.
json.NewDecoder(reader).Decode(&p1)
main.go package main import ( "encoding/json" "fmt" "strings" ) type person struct { Name string Age int address int //this field will not be exported } func main() { var p1 person reader := strings.NewReader(`{"Name":"James", "Age":24, "address":"New York"}`) // JSON json.NewDecoder(reader).Decode(&p1) fmt.Println(p1.Name) fmt.Println(p1.Age) fmt.Println(p1.address) }
Golang’s standard library has provided built-in functions to deal with strings in the “strings” package.
“Computer” → This string has 8 runes. So no need of counting for finding its length as there is built-in function len( ) for calculating its length.
In Golang, we use len( ) for a slice, array, map for measuring their length. So this makes the language more clear and understandable.
func main(){ var s string=”Computer” fmt.Println(len(s)) }
More functions – https://golang.org/pkg/strings/
main.go package main import "fmt" import s "strings" //we can also give prefixes and use import "strings" //also we can use normally var b = fmt.Println //prefix for fmt.Println() func main() { var str string = "Computer-Security" fmt.Println(len(str)) //length: 18 fmt.Println("Contains:", s.Contains(str, "ecu")) //true fmt.Println("Compare:", s.Compare(str, "Computer Security")) /*return 0 if a==b,-1 if a<b,+1 if a>b*/ fmt.Println("Count", strings.Count(str, "e")) //returns 2 b("Index:", s.Index(str, "m")) // returns 2 b("ToLower", strings.ToLower(str)) b("ToUpper", strings.ToUpper(str)) b("Replace", s.Replace(str, "e", "i", 2)) /* replace e by i for 2 Occurrences */ b("Split", strings.Split(str, "-")) }
An interface is an abstract type. It doesn’t expose the representation or internal structure of its values, or set of basic operation they support; it reveals only some of their methods. When you have value of an interface type, you don’t know only what it is; you only know what it can do.
Interfaces are named collection of method signatures only (like java). To implement an interface in Go, we need to implement all the methods of that interface.
Like a struct, we can create interface by specifying type keyword followed by its name and keyword interface that will contain methods.
type interface_name interface{ /* method signature (one or more method sets) */ }
Example –
type shape interface{ area( ) float64 //method } /* interface creation with method declaration
Now anything that has same method signature implements interface like –
type square struct { side float64 } func (sq square) area( ) float64 { //area( ) associated with square struct Return sq.side * sq.side }
In above sample example, area( ) associated with square struct has same signature like shape interface area( ) that means shape interface is implemented by square struct.
See the below example,
shapeI.go package IShape type Shape interface { Area() float64 }
CircleI.go package SCircle import ("math") type Circle struct { Radius float64 } func (c Circle) Area() float64 { //Here, Area( )is implemented return math.Pi * c.Radius * c.Radius }
SquareI.go package SSquare type Square struct { Side float64 } func (s Square) Area() float64 { //Here, Area( )is implemented return s.Side * s.Side }
main.go package main import ( "fmt" "interface/basic/IShape" /* These are packages I’ve created */ "interface/basic/SCircle" "interface/basic/SSquare" ) func info(s IShape.Shape) { /* Now here info( ) will accept dynamically any of type of square or circle because Shape is implemented by both of them*/ fmt.Println(s) fmt.Println(s.Area()) } func main() { s := SSquare.Square{10} info(s) /* Here, I’ve passed square type */ c := SCircle.Circle{7} info(c) /* Here, I’ve passed circle type */ }
This is what we call Polymorphism. Polymorphism is the ability to write code that takes on different behaviour through its implementation of types.
When you are passing an interface value, then there is no guarantee whether interface type is or isn’t pointer. In the above example, we created function based on value receiver and we passed associated values of square or circle to it.
Just take method with pointer receiver.
func (c *Circle) Area() float64 { }
Now if we try to pass interface value to it, it will give an error
Circle does not implement Shape(Area method requires pointer receiver). So for the pointer receivers, we need to pass the *Circle pointer to the Shape instead of a Circle value, by using new(Circle) or &Circle.
Interfaces are types that just declare the behavior. This behavior is never implemented by interface directly, but instead by user defined types; values of user defined type can be assigned to values & interface type. This assignment stores values of user defined type into interface value. – Bill Kenedy
Interfaces can also be used as fields.
type struct MultiShape{ shapes [ ]Shape }
If you see “bufio” and “ioutil” package in Go’s language specification, you’ll get something like this –
func NewScanner(r io.Reader) *Scanner
→ bufio.NewScanner(res.Body)
→ In the Body interface, ReadCloser interface is implemented which again implements Reader interface that means Indirectly we are dealing with the Reader.
func ReadAll(r io.Reader) ([]byte, error)
→ ioutil.ReadAll(res.Body)
→ Same as above
func NewReader(rd io.Reader) *Reader
We need to define a meaningful name & type for fields or properties. We can initialize fields with its value or can keep blank so it will use default value.
In other languages (like Java), we have to explicitly say that this interface is implemented by other. But in Go interfaces are implemented implicitly so you don’t need to say like that you just need to use the correct method signature to use from interface.
type ReaderWriter { Reader Writer } /* This is called embedding of interfaces */
A type satisfies an interface if it possesses all methods that interface requires. Conceptually, value of interface type or interface value has two components – A concrete type and concrete value.
“Sort” package has an interface called type Interface. Sort package provides sorting of any sequence according to ordering function. Go’s Sort function assumes nothing about the representation of the sequence. Instead, it uses sort.interface for specifying sorting sequence and sorting algorithm.
An in-place algorithm needs 3 things – length of sequence for comparing two elements and way to swap two elements- so it contains 3 methods.
package sort type Interface interface{ Len( ) int Less(i,j int) bool Swap(i,j int) /* Method sets */ }
So if you want to use sorting then we need to implement these methods from sort. Interface package and then apply Sort( ) on it.
Package sort provided primitives for sorting slices and user-defined collection.
main.go package main import ( "fmt" "sort" ) type Person struct { Name string Age int } type ByAge []Person /*This type of []Person has implemented sort.Interface interface*/ func (b ByAge) Len() int { return len(b) } func (b ByAge) Swap(i, j int) { b[i], b[j] = b[j], b[i] } func (b ByAge) Less(i, j int) bool { return b[i].Age > b[j].Age } func main() { persons := []Person{ {"George", 34}, {"Robin", 43}, {"Stuart", 23}} peoples := []string{"Keyboard", "mouse", "Computer"} rev := []string{"Book", "Literature", "Novel"} ints := []int{54, 76, 33, 12, 54, 76} fmt.Println("Before Sort:", persons) fmt.Println("Before Sort:", peoples) sort.Strings(peoples) /* Sorting string slice */ sort.Sort(sort.Reverse(sort.StringSlice(rev))) fmt.Println("Reversed String Slice", rev) sort.Sort(sort.IntSlice(ints)) fmt.Println("Sorted Integer value", ints) fmt.Println("After Sort:", peoples) sort.Sort(ByAge(persons)) fmt.Println("After Sort:", persons) }
Empty interface has zero methods. It is like Object class (which is superclass of all classes in java and accept any object). Similar to this, empty interface accepts any interface to itself.
An empty interface can hold any hold values of any type.
Empty interfaces are used by code that handles values of any type.
For example, fmt.Println(a …interface{ }) (n int,err error) takes any type number of arguments of type interface{ }.
main.go package main import ( "fmt" ) type vehicles interface{ } //Empty interface type vehicle struct { speed string color string } type car struct { vehicle wheels int doors int } type plane struct { vehicle jet bool } type boat struct { vehicle capacity int } func specifications(veh interface{}) { /* accepting anything*/ fmt.Println(veh) } func main() { audiR8 := car{vehicle{"240 KMPH", "White"}, 4, 4} benz := car{vehicle{"250 KMPH", "Black"}, 4, 4} boeing := plane{vehicle{"500 KMPH", "White"}, true} sanger := boat{vehicle{"350 KMPH", "Saffron"}, 10000} travelling := []vehicles{audiR8, benz, boeing, sanger} for key, value := range travelling { fmt.Println(key, "-", value) } specifications(audiR8) specifications(benz) specifications(boeing) specifications(sanger) }
Conversion is converting to one type from another type like int to float. Assertion is different from conversion.
Conversion process deals with two concepts like –
Example –
var x=15 //int type var y=15.45 fmt.Println(float(x)) → 15.00 fmt.Println(int(y)) → 15
var x rune=’a’ var y int32=’b’ fmt.Println(x) fmt.Println(y) fmt.Println(string(x)) →a fmt.Println(string(y)) →b
Now come to an assertion, sometimes you want to know the exact type of interface variable, in this case, you have to use type assertion.
interface_variable.(type)
main.go package main import “fmt” func display(v interface{ }){ fmt.Printf(“Value is:%v”,v.(int)) /*assert or test the correct va*/ } func main(){ display(10) }
O/P: 10
But here, if we put v.(string) then we will get running panic error
panic: interface conversion: interface {} is int, not string
goroutine 1 [running]:
main.display(0x497e00, 0xc0420361c0)
For this, assertion actually returns a boolean value to tell whether this operation holds or not
main.go package main import “fmt” func display(v interface{ }){ if v,ok:=v.(string);ok { fmt.Printf(“Value is:%v”,v.(int)) /*assert/test the correct val*/ }else{ fmt.Println(“Value is not string”) } } func main(){ display(10) }
O/P: Value is not string
This time o/p will be “value is not string” instead of getting a panic error. We can also use a type switch
How to Effectively Hire and Manage a Remote Team of Developers.
Download NowMaster Epic Integration with SMART on FHIR in Just 60 Minutes
Register HereMindbowser played a crucial role in helping us bring everything together into a unified, cohesive product. Their commitment to industry-standard coding practices made an enormous difference, allowing developers to seamlessly transition in and out of the project without any confusion....
CEO, MarketsAI
I'm thrilled to be partnering with Mindbowser on our journey with TravelRite. The collaboration has been exceptional, and I’m truly grateful for the dedication and expertise the team has brought to the development process. Their commitment to our mission is...
Founder & CEO, TravelRite
The Mindbowser team's professionalism consistently impressed me. Their commitment to quality shone through in every aspect of the project. They truly went the extra mile, ensuring they understood our needs perfectly and were always willing to invest the time to...
CTO, New Day Therapeutics
I collaborated with Mindbowser for several years on a complex SaaS platform project. They took over a partially completed project and successfully transformed it into a fully functional and robust platform. Throughout the entire process, the quality of their work...
President, E.B. Carlson
Mindbowser and team are professional, talented and very responsive. They got us through a challenging situation with our IOT product successfully. They will be our go to dev team going forward.
Founder, Cascada
Amazing team to work with. Very responsive and very skilled in both front and backend engineering. Looking forward to our next project together.
Co-Founder, Emerge
The team is great to work with. Very professional, on task, and efficient.
Founder, PeriopMD
I can not express enough how pleased we are with the whole team. From the first call and meeting, they took our vision and ran with it. Communication was easy and everyone was flexible to our schedule. I’m excited to...
Founder, Seeke
Mindbowser has truly been foundational in my journey from concept to design and onto that final launch phase.
CEO, KickSnap
We had very close go live timeline and Mindbowser team got us live a month before.
CEO, BuyNow WorldWide
If you want a team of great developers, I recommend them for the next project.
Founder, Teach Reach
Mindbowser built both iOS and Android apps for Mindworks, that have stood the test of time. 5 years later they still function quite beautifully. Their team always met their objectives and I'm very happy with the end result. Thank you!
Founder, Mindworks
Mindbowser has delivered a much better quality product than our previous tech vendors. Our product is stable and passed Well Architected Framework Review from AWS.
CEO, PurpleAnt
I am happy to share that we got USD 10k in cloud credits courtesy of our friends at Mindbowser. Thank you Pravin and Ayush, this means a lot to us.
CTO, Shortlist
Mindbowser is one of the reasons that our app is successful. These guys have been a great team.
Founder & CEO, MangoMirror
Kudos for all your hard work and diligence on the Telehealth platform project. You made it possible.
CEO, ThriveHealth
Mindbowser helped us build an awesome iOS app to bring balance to people’s lives.
CEO, SMILINGMIND
They were a very responsive team! Extremely easy to communicate and work with!
Founder & CEO, TotTech
We’ve had very little-to-no hiccups at all—it’s been a really pleasurable experience.
Co-Founder, TEAM8s
Mindbowser was very helpful with explaining the development process and started quickly on the project.
Executive Director of Product Development, Innovation Lab
The greatest benefit we got from Mindbowser is the expertise. Their team has developed apps in all different industries with all types of social proofs.
Co-Founder, Vesica
Mindbowser is professional, efficient and thorough.
Consultant, XPRIZE
Very committed, they create beautiful apps and are very benevolent. They have brilliant Ideas.
Founder, S.T.A.R.S of Wellness
Mindbowser was great; they listened to us a lot and helped us hone in on the actual idea of the app. They had put together fantastic wireframes for us.
Co-Founder, Flat Earth
Ayush was responsive and paired me with the best team member possible, to complete my complex vision and project. Could not be happier.
Founder, Child Life On Call
The team from Mindbowser stayed on task, asked the right questions, and completed the required tasks in a timely fashion! Strong work team!
CEO, SDOH2Health LLC
Mindbowser was easy to work with and hit the ground running, immediately feeling like part of our team.
CEO, Stealth Startup
Mindbowser was an excellent partner in developing my fitness app. They were patient, attentive, & understood my business needs. The end product exceeded my expectations. Thrilled to share it globally.
Owner, Phalanx
Mindbowser's expertise in tech, process & mobile development made them our choice for our app. The team was dedicated to the process & delivered high-quality features on time. They also gave valuable industry advice. Highly recommend them for app development...
Co-Founder, Fox&Fork