关于写习语咕噜的几点建议 [英] Advice on writing idiomatic Golang

查看:22
本文介绍了关于写习语咕噜的几点建议的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在掌握戈朗的做事方式。首先是一些示例代码:

package main

import (
    "log"
    "os"
)

func logIt(s string) {
    f, _ := os.OpenFile("errors.log", os.O_RDWR|os.O_CREATE|os.O_APPEND,
        0666)
    defer f.Close()

    log.SetOutput(f)
    log.Println(s)
}

type iAm func(string)

func a(iam string) { logIt(iam + " A") }

func b(iam string) { logIt(iam + " B") }

func c(iam string) { logIt(iam + " C") }

var funcs = map[string]iAm{"A": a, "B": b, "C": c}

func main() {
    funcs["A"]("Je suis")
    funcs["B"]("Ich bin")
    funcs["A"]("Yo soy")
    funcs["D"]("Soy Yo")
}

说明

  • 我正在将我所有的注销输出传输到一个文件中,以便我以后可以监视它。这是正确的引导方式吗?
  • 我希望根据用户输入确定在运行时要调用的正确函数。为此,我将函数打包为Golang映射-在PHP中,我会使用关联数组。这很管用。然而,这是一种高效的做事方式吗?
  • 最后,您会注意到我的映射中实际上没有D键。最后一个函数调用导致GO抛出抖动。换成另一种语言,我会试着把这些电话包起来……块,并避免了该问题。据我所知,围棋的理念是首先检查密钥的有效性,然后惊慌失措,而不是试图盲目使用该密钥。对吗?

我是围棋初学者,所以我可能有来自我使用的其他语言的包袱。在我看来,以先发制人的方式处理异常情况(在使用之前检查密钥)既不聪明也不高效。对吗?

推荐答案

登录到文件

我不会在每次要记录内容时打开和关闭文件。在启动时,我只会打开它一次并将其设置为输出,然后在程序存在之前关闭它。我不会使用logIt()函数:只需使用log包的函数进行日志记录,因此您可以使用log.Printf()等进行格式化日志记录。

动态功能选择

函数映射完全正常,并且在性能方面做得很好。如果您需要更快的功能,可以根据函数名执行switch,直接调用case分支中的目标函数。

检查密钥是否存在

map中的值是函数值。函数类型的零值是nil,您不能调用nil函数,因此在继续调用它之前必须检查该值。请注意,如果使用不存在的键对映射进行索引,则返回值类型的零值,如果是函数类型,则为nil。因此,我们只需检查该值是否为nil。还有另一个逗号OK习惯用法,例如fv, ok := funcs[name],其中ok将是一个布尔值,用于告诉是否在映射中找到了键。

您可以在一个地方完成,但不必在每次调用中复制:

func call(name, iam string) {
    if fv := funcs[name]; fv != nil {
        fv(iam)
    }
}

注意:

如果您选择使用switchdefault分支将处理无效的函数名称(这里当然不需要函数映射):

func call(name, iam string) error {
    switch name {
    case "A":
        a(iam)
    case "B":
        b(iam)
    case "C":
        c(iam)
    default:
        return errors.New("Unknown function: " + name)
    }
    return nil
}

错误处理/报告

在Go中,函数可以有多个返回值,因此在Go中,您通过返回error值来传播错误,即使该函数通常具有其他返回值。

因此,call()函数应具有error返回类型,以便在找不到指定函数时发出信号。

您可以选择返回由errors.New()函数创建的新error值(因此它可以是动态的),也可以选择创建全局变量并具有固定的错误值,如下所示:

var ErrInvalidFunc = errors.New("Invalid function!")

此解决方案的优点是,call()函数的调用方可以将返回的error值与ErrInvalidFunc全局变量的值进行比较,以了解情况是否如此,并采取相应的操作,例如:

if err := call("foo", "bar"); err != nil {
    if err == ErrInvalidFunc {
        // "foo" is an invalid function name
    } else {
        // Some other error
    }
}

所以完整的修订方案:

(稍微压缩以避开垂直滚动条)

package main

import ("errors"; "log"; "os")

type iAm func(string)

func a(iam string) { log.Println(iam + " A") }
func b(iam string) { log.Println(iam + " B") }
func c(iam string) { log.Println(iam + " C") }

var funcs = map[string]iAm{"A": a, "B": b, "C": c}

func main() {
    f, err := os.OpenFile("errors.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
    if err != nil {
        panic(err)
    }
    defer f.Close()
    log.SetOutput(f)

    call("A", "Je suis")
    call("B", "Ich bin")
    call("C", "Yo soy")
    call("D", "Soy Yo")
}

func call(name, iam string) error {
    if fv := funcs[name]; fv == nil {
        return errors.New("Unknown funcion: " + name)
    } else {
        fv(iam)
        return nil
    }
}

这篇关于关于写习语咕噜的几点建议的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆