如何在 Go 中迭代自定义类型的数组?

Tra*_*vis 0 go

我在代码中创建了一个客户类型。我有一个函数,它正在读取一个 csv 文件并从每一行创建一个数组。

type DesiredService struct {
    Name string `json:"Name"`
    Status string `json:"Status"`
}
Run Code Online (Sandbox Code Playgroud)

如果我打印出变量,我有一些看起来像 [{app1 active}{app2 active}]

我不知道如何获取该变量并遍历每个索引。我需要获取状态为 active 的所有条目并调用另一个函数来根据 API 检查名称。我在想也许我没有正确设置结构。

当我检查它返回的变量类型时 []main.DesiredService

在阅读了一些文档后,这就是我想出的不起作用的东西。

func checkPagerDutyforService (serviceList []DesiredService) (bool){
    var serviceExist bool()
    for i, v := range serviceList {
        if v == "active" {
            checkIfServiceExist(i, serviceList)
            serviceExist = true
        } else {
            if v != "active"{
                serviceExist = false
            }
        }
    }
    return serviceExist
Run Code Online (Sandbox Code Playgroud)

Sch*_*ern 9

我需要获取状态为 active 的所有条目并调用另一个函数来根据 API 检查名称。

在 Go 中,您使用循环进行迭代for,通常使用该range函数。

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\n", service);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,range返回索引(即 0、1、2)和实际元素。如果你只想索引它for i := range services,但如果你只想元素它for _,service := range services与_告诉转到您不希望返回值。

range是 Go 非常强大和灵活的核心特性。如果您还没有range读过 ,我建议您至少停下来阅读A Tour of Go和Go By Example,其中将涵盖这样的基本功能。然后阅读Effective Go了解详情。


请注意,JSON 字段标记是不必要的。默认情况下Name,JSON已自动将该字段编组为 JSON 字段Name。所以它们可以省略。如果您想将其更改为,name则可以使用标签。


您正在尝试的代码存在许多问题。

  • v == "active":v是一个 DesiredService 结构。要检查其状态字段,它是v.Status == "active".
  • else { if v != "active": 这是多余的if v == "active"。如果else根据定义您在该块中v == "active"。
  • return serviceExist:这是由每次循环迭代设置的,因此它只会反映serviceList.

这是你如何处理这个。

// 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
}
Run Code Online (Sandbox Code Playgroud)

请注意,它在找到活动服务后立即返回,而不是遍历整个列表。一旦找到服务,就无需再进一步。

getActiveService出于两个原因,我已将其更改为。这里没有关于寻呼机的任何内容,所以大概它可以处理任何类型的服务列表。其次,返回一个布尔值就像说“是的,这个列表中有一个活跃的服务”,自然的下一个问题是“好吧,聪明的家伙,哪个?!” 既然我们已经完成了工作,不妨返回一个活跃的服务。

这将返回值从简单的布尔值稍微更改为*DesiredService. “获取”功能有时无法获取您想要的东西。但是DesiredService类型说你总是会返回一个DesiredService. 如果没有活动服务,DesiredService我们可以通过将它作为对 a 的引用返回nil。

service := getActiveService(services);
if service != nil {
    fmt.Println(service)
} else {
    fmt.Println("No active service")
}
Run Code Online (Sandbox Code Playgroud)

*DesiredService是对DesiredService非副本的引用。Go 将消除事物和对事物的引用之间的差异,使用引用没有特殊的语法。但是,请注意,您使用的不是副本。您所做的任何更改都service将反映在services列表中。

// This will affect the entry in services as well.
service.Name = "something else"
Run Code Online (Sandbox Code Playgroud)

使用error类型返回更详细的错误。


下一步将是滚动service.Status == "active" && pingService(service)到单一方法上,DesiredService以便服务知道如何检查自己。那么任何使用 DesiredService 的人都不需要知道这些细节,如果他们改变,细节就在一个地方。

func (self DesiredService) isActive() bool {
    return self.Status == "active" && self.Ping()
}
Run Code Online (Sandbox Code Playgroud)

Ping 也是服务应该对自己做的事情。

// Just a placeholder. Presumably this will ping the
// service or something.
func (self DesiredService) Ping() bool {
    return true
}
Run Code Online (Sandbox Code Playgroud)

然后getActiveService询问service它是否处于活动状态。

func getActiveService (serviceList []DesiredService) *DesiredService {
    for _, service := range serviceList {
        if service.isActive() {
            return &service
        }
    }

    return nil
}
Run Code Online (Sandbox Code Playgroud)