Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Go 参数太多,无法返回错误_Go - Fatal编程技术网

Go 参数太多,无法返回错误

Go 参数太多,无法返回错误,go,Go,我一直在想为什么这段代码会抛出错误: package util import ( "path/filepath" "sync" "github.com/go-ini/ini" ) // ConfigMap is map for config values type ConfigMap struct { LogPath string PublicDir string SessionName string D

我一直在想为什么这段代码会抛出错误:

package util

import (
   "path/filepath"
   "sync"

   "github.com/go-ini/ini"
)

// ConfigMap is map for config values
type ConfigMap struct {
    LogPath         string
    PublicDir       string
    SessionName     string
    Debug           bool
    DBUsersHost     string
    DBUsersName     string
    DBUsersUsername string
    DBUsersPassword string
}

var once sync.Once

// Config loads and return config object
func Config() (*ConfigMap, error) {
    once.Do(func() {
        // Find the location of the app.conf file
        configFilePath, err := filepath.Abs("../build/app.conf")
        if err != nil {
            return nil, err
        }

        // Load app.conf
        cfg, err := ini.Load(configFilePath)
        if err != nil {
            return nil, err
        }

        // Get app mode
        mode, err := AppMode()
        if err != nil {
            return nil, err
        }

        c := &ConfigMap{}
        err = cfg.Section(mode).MapTo(c)
        if err != nil {
            return nil, err
        }

        return c, err
    })
}

如您所见,配对完全正确。每个返回代码返回&ConfigMap和err,函数签名与之匹配。我遗漏了什么?

将匿名函数值传递给once。执行该操作,返回语句就在其中。这意味着这些返回语句希望从匿名函数返回,但它没有任何返回值:

func Config() (*ConfigMap, error) {
    once.Do(func() {
        // You can't return any values here, only this works:
        return
    })

    // And you do need to return something here:
    return &ConfigMap{}, nil
}
您可以创建与Config的返回值匹配的全局变量,匿名函数应该将这些值存储在其中。在Config中,您可以返回这些全局变量的值

var cm *ConfigMap
var cmErr error

func Config() (*ConfigMap, error) {
    once.Do(func() {
        // load config, and store, e.g.
        cm, cmErr = &ConfigMap{}, nil
    })

    return cm, cmErr
}
我们真的需要全局变量吗?由于Config返回的值是由传递给once.Do的匿名函数生成的,而once.Do保证只运行一次。是的,您需要将它们存储在某个位置,以便能够多次返回它们,即使在以后调用Config时不再调用/运行匿名函数

问:这里可能会有数据竞赛吗

如果从多个goroutine调用Config,则至少有一个将写入全局变量cm和cmErr,所有变量都将读取它们。所以问这个问题是正确的

但是答案是否定的,上面的代码是安全的。全局变量cm和cmErr只写入一次,并且在读取它们之前就会发生这种情况。因为一次.Do阻塞直到匿名函数返回。如果从多个goroutine同时调用Config和one.Do,则所有函数都将阻塞,直到匿名函数只完成一次,并且只有在第一次写入之后才能读取变量。由于匿名函数将不再运行,因此不会再发生写入操作。

您正在从once.Do中的嵌套func调用return nil、err和类似函数。相反,您并不是从实际函数返回

相反,您可以这样构造代码:

func newConfig() (*Config, error) {
    configFilePath, err := filepath.Abs("../build/app.conf")
    if err != nil {
        return nil, err
    }

    // Load app.conf
    cfg, err := ini.Load(configFilePath)
    if err != nil {
        return nil, err
    }

    // Get app mode
    mode, err := AppMode()
    if err != nil {
        return nil, err
    }

    c := &ConfigMap{}
    err = cfg.Section(mode).MapTo(c)
    if err != nil {
        return nil, err
    }

    return c, err
}

// Cached config and any error.
var (
   cachedConfig *Config
   cachedConfigErr error
)

func Config() (*Config, error) {
  once.Do(func() {
    cachedConfig, cachedConfigErr = newConfig()
  })
  return cachedConfig, cachedConfigErr
}