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

时间:2018-02-08 19:16:53

标签: go

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

type DesiredService struct {
    Name string `json:"Name"`
    Status string `json:"Status"`
}

如果我打印出变量,我会看到一些东西 [{app1 active}{app2 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

1 个答案:

答案 0 :(得分:1)

  

我需要使用状态为活动状态的所有条目,并调用另一个函数来检查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);
        }
    }
}

注意range返回索引(即0,1,2)和实际元素。如果您只想要索引for i := range services,但是如果您只想要for _,service := range services的元素,而_告诉Go您不希望返回值。

range是Go的强大而灵活的核心功能。如果您还没有range,我建议至少停止并阅读A Tour of GoGo By Example,这将涵盖此类基本功能。然后阅读Effective Go了解详细信息。

请注意,JSON字段标记是不必要的。默认情况下,JSON将自动封送字段Name作为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
}

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

我将其更改为getActiveService有两个原因。这里没有关于寻呼机的信息,因此可能它可以处理任何类型服务的列表。第二,返回一个bool就像是说“是的,这个列表中有一个活跃的服务”,自然的下一个问题是“好的,自作聪明,哪一个?!”既然我们已经完成了工作,也可以返回一个有效的服务。

这会将返回值从简单布尔值更改为*DesiredService。 “获取”功能有时无法获得您想要的功能。但DesiredService类型表示您将始终返回DesiredService。通过将其作为DesiredService的引用,如果没有有效服务,我们可以返回nil

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

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

// This will affect the entry in services as well.
service.Name = "something else"

Further detailed errors are returned using the error type

下一步是将service.Status == "active" && pingService(service)转入a single method on DesiredService,以便服务知道如何自行检查。然后,使用DesiredService的任何人都不需要知道这些细节,如果细节发生变化,细节就在一个地方。

func (self DesiredService) isActive() bool {
    return self.Status == "active" && self.Ping()
}

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

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

然后getActiveService询问service是否有效。

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

    return nil
}