从重复范围创建函数

I have a some structs like so:

type Datacenter struct {
  Name  string
  Key   string
  Hosts []Host
}

type Host struct {
  Name string
  Port int
}

When these structs are populated, they look like this:

[]config.Datacenter (len=2) {
  Datacenter {
    Name: "dc1",
    Key: "string",
    Hosts: []config.Host (len=1) {
      Host {
        Name: "dc1-server-1",
        Port: 8200 (int)
      }
    }
  },
  Datacenter {
    Name: "dc2",
    Key: "Another string",
    Hosts: []config.Host (len=2) {
      Host {
        Name: "dc2-server-1",
        Port: 8200 (int)
      },
      Host {
        Name: "dc2-server-2",
        Port: 8200 (int)
      }
    }
  }
}

I am creating a CLI tool, and for almost every command, I range over these structs in this manner:

for _, d := range datacenters {
  if datacenter == d.Name || datacenter == "" {
    for _, h := range d.Hosts {
      // do something on each host in the range here
    }
  }
}

Because I'm an awful, awful go developer, I know there is a better way to do this. The code is not very DRY at the moment, I am literally coping and pasting the range into each new subcommand, which looks awful and generally makes me feel stupid.

I think I need to creation a function and do the ranging inside that, and then decide on the return values. I just can't figure out what it should be, the concepts aren't there. Any help will be greatly appreciated.

It sounds like you want to do something like:

func EachHost(datacenter string, f func(Host)) {
    for _, d := range datacenters {
        if datacenter == d.Name || datacenter == "" {
            for _, h := range d.Hosts {
                // do something on each host in the range here
                f(h)
            }
        }
     }
}

And then you can do something like:

listHostNames := func(datacenter string) {
    EachHost(datacenter, func(h Host) {
        fmt.Println(h.Name)
    });
}
listHostNames("dc1")