I need to take all of the entries with a Status of active and call another function to check the name against an API.
In Go you iterate with a for
loop, usually using the range
function.
package main
import (
"fmt"
)
type DesiredService struct {
// The JSON tags are redundant here. See below.
Name string `json:"Name"`
Status string `json:"Status"`
}
func main() {
services := []DesiredService{
DesiredService{"foo", "Active"},
DesiredService{"bar", "Active"},
DesiredService{"baz", "Inactive"},
}
for _,service := range services {
if service.Status == "Active" {
fmt.Printf("%#v
", service);
}
}
}
Note that range
returns the index (ie. 0, 1, 2) and the actual element. If you want just the index it's for i := range services
but if you want just the element it's for _,service := range services
with the _
telling Go that you don't want that return value.
range
is very powerful and flexible core feature of Go. If you haven't gotten to range
, I'd recommend stopping and reading at least A Tour of Go and Go By Example which will cover basic functionality like this. Then read Effective Go for the details.
Note that the JSON field tags are unnecessary. JSON will already automatically marshal the field Name
as the JSON field Name
by default. So they can be omitted. If you wanted to change it to name
then you'd use a tag.
There's a number of problems with the code you're trying.
-
v == "active"
: v
is a DesiredService struct. To check its Status field it's v.Status == "active"
.
-
else { if v != "active"
: This is redundant with if v == "active"
. If you're in that else
block by definition v == "active"
.
-
return serviceExist
: This is set by every loop iteration, so it will only reflect the last element in serviceList
.
Here's how you'd handle this.
// Just a placeholder. Presumably it will ping the service
// to ensure it's really working.
func pingService( service DesiredService ) bool {
return true
}
func getActiveService (services []DesiredService) *DesiredService {
for _, service := range services {
if service.Status == "active" && pingService(service) {
return &service
}
}
return nil
}
Note that it returns immediately upon finding an active service, rather than iterating through the whole list. Once it's found a service there's no need to go further.
I've changed it to getActiveService
for two reasons. There's nothing in here about pagers, so presumably it can handle lists of any types of services. And second, returning a bool is like saying "yes, there is an active service in this list" and the natural next question is "ok, smart ass, which one?!" Since we've gone through the work anyway, might as well return an active service.
This changes the return value a bit from a simple boolean to *DesiredService
. "Get" functions sometimes can't get what you want. But the DesiredService
type says you will always return a DesiredService
. By making it a reference to a DesiredService
we can return nil
if there's no active service.
service := getActiveService(services);
if service != nil {
fmt.Println(service)
} else {
fmt.Println("No active service")
}
*DesiredService
is a reference to DesiredService
not a copy. Go will smooth out the difference between a thing and a reference to a thing, there's no special syntax for working with a reference. However, be aware that you're not working with a copy. Any changes you make to service
will reflect on the services
list.
// This will affect the entry in services as well.
service.Name = "something else"
Further detailed errors are returned using the error
type.
The next step would be to roll service.Status == "active" && pingService(service)
into a single method on DesiredService
so services know how to check themselves. Then anyone using a DesiredService doesn't need to know these details, and the details are in one place should they change.
func (self DesiredService) isActive() bool {
return self.Status == "active" && self.Ping()
}
Pinging is also something a service should do to itself.
// Just a placeholder. Presumably this will ping the
// service or something.
func (self DesiredService) Ping() bool {
return true
}
Then getActiveService
asks the service
if it is active.
func getActiveService (serviceList []DesiredService) *DesiredService {
for _, service := range serviceList {
if service.isActive() {
return &service
}
}
return nil
}