惯用语 Go Happy Path
Idiomatic Go Happy Path
假设我们有一个函数 return 有一些值和一个错误。处理错误和值声明的首选方式是什么?
func example_a(data interface{}) (interface{}, error) {
var err error
var bytes []byte
if bytes, err = json.Marshal(data); err != nil {
return nil, err
}
// ...
return use(bytes), nil
}
func example_b(data interface{}) (interface{}, error) {
if bytes, err := json.Marshal(data); err != nil {
return nil, err
} else {
// ...
return use(bytes), nil
}
}
func example_c(data interface{}) (result interface{}, err error) {
var bytes []byte
if bytes, err = json.Marshal(data); err != nil {
return
}
// ...
return use(bytes), nil
}
func example_d(data interface{}) (interface{}, error) {
bytes, err := json.Marshal(data)
if err != nil {
return nil, err
}
// ...
return use(bytes), nil
}
func example_dream(data interface{}) (interface{}, error) {
if bytes, err ≡ json.Marshal(data); err != nil {
return nil, err
}
// ...
return use(bytes), nil
}
示例 A 很清楚,但它增加了 2 行。此外,我发现不清楚为什么在这种特殊情况下我们应该使用 var
,同时 :=
并不总是合适的。然后你想在某处重用 err
声明,我不喜欢拆分声明和赋值。
示例 B 使用了 if-declare-test 语言特性,我认为这是值得鼓励的,但同时你被迫嵌套函数继续,违反了 happy-路径原则,这也是被鼓励的。
示例 C 使用命名参数 return 特性,它介于 A 和 B 之间。这里最大的问题是,如果您的代码库使用样式 B和C,那么很容易弄错:=
和=
,会导致各种问题。
示例 D(根据建议添加)对我来说有与 C 相同的使用问题,因为我不可避免地 运行 进入以下内容:
func example_d(a, b interface{}) (interface{}, error) {
bytes, err := json.Marshal(a)
if err != nil {
return nil, err
}
bytes, err := json.Marshal(b) //Compilation ERROR
if err != nil {
return nil, err
}
// ...
return use(bytes), nil
}
因此,根据之前的声明,我必须修改我的代码以使用 :=
或 =
,这使得查看和重构变得更加困难。
Example Dream 是我直觉上对 GO 的期望——没有嵌套,快速退出,没有太多冗长和变量重用。显然它不能编译。
通常 use()
被内联并多次重复该模式,使嵌套或拆分声明问题更加复杂。
那么,处理此类多个 return 和声明的最惯用的方法是什么?有没有我遗漏的模式?
如果你查看大量 Go 代码,你会发现以下是常见的情况:
func example(data interface{}) (interface{}, error) {
bytes, err := json.Marshal(data)
if err != nil {
return nil, err
}
// ...
return use(bytes), nil
}
declare and test if 构造在它的位置上很好,但在这里通常不合适。
假设我们有一个函数 return 有一些值和一个错误。处理错误和值声明的首选方式是什么?
func example_a(data interface{}) (interface{}, error) {
var err error
var bytes []byte
if bytes, err = json.Marshal(data); err != nil {
return nil, err
}
// ...
return use(bytes), nil
}
func example_b(data interface{}) (interface{}, error) {
if bytes, err := json.Marshal(data); err != nil {
return nil, err
} else {
// ...
return use(bytes), nil
}
}
func example_c(data interface{}) (result interface{}, err error) {
var bytes []byte
if bytes, err = json.Marshal(data); err != nil {
return
}
// ...
return use(bytes), nil
}
func example_d(data interface{}) (interface{}, error) {
bytes, err := json.Marshal(data)
if err != nil {
return nil, err
}
// ...
return use(bytes), nil
}
func example_dream(data interface{}) (interface{}, error) {
if bytes, err ≡ json.Marshal(data); err != nil {
return nil, err
}
// ...
return use(bytes), nil
}
示例 A 很清楚,但它增加了 2 行。此外,我发现不清楚为什么在这种特殊情况下我们应该使用 var
,同时 :=
并不总是合适的。然后你想在某处重用 err
声明,我不喜欢拆分声明和赋值。
示例 B 使用了 if-declare-test 语言特性,我认为这是值得鼓励的,但同时你被迫嵌套函数继续,违反了 happy-路径原则,这也是被鼓励的。
示例 C 使用命名参数 return 特性,它介于 A 和 B 之间。这里最大的问题是,如果您的代码库使用样式 B和C,那么很容易弄错:=
和=
,会导致各种问题。
示例 D(根据建议添加)对我来说有与 C 相同的使用问题,因为我不可避免地 运行 进入以下内容:
func example_d(a, b interface{}) (interface{}, error) {
bytes, err := json.Marshal(a)
if err != nil {
return nil, err
}
bytes, err := json.Marshal(b) //Compilation ERROR
if err != nil {
return nil, err
}
// ...
return use(bytes), nil
}
因此,根据之前的声明,我必须修改我的代码以使用 :=
或 =
,这使得查看和重构变得更加困难。
Example Dream 是我直觉上对 GO 的期望——没有嵌套,快速退出,没有太多冗长和变量重用。显然它不能编译。
通常 use()
被内联并多次重复该模式,使嵌套或拆分声明问题更加复杂。
那么,处理此类多个 return 和声明的最惯用的方法是什么?有没有我遗漏的模式?
如果你查看大量 Go 代码,你会发现以下是常见的情况:
func example(data interface{}) (interface{}, error) {
bytes, err := json.Marshal(data)
if err != nil {
return nil, err
}
// ...
return use(bytes), nil
}
declare and test if 构造在它的位置上很好,但在这里通常不合适。