Golang中哪种"return"写法更好?

Golang中哪种"return"写法更好? 抱歉问这么简单的问题:

哪种"return"方式性能更好或您通常使用哪种?(当您有很多返回值时)

这里是代码示例:

Go Playground - The Go Programming Language

还有下面的代码:

A

func getInfo(a int, b string , c bool, d int ) (aa int , bb string , cc bool, dd int){
    	a = aa
    	b = bb
    	c = cc
    	d = dd
    	return
    }

B

func getInfo2(a int, b string , c bool, d int ) ( int ,string , bool,  int) {
    	
    	if "ok" == "ok" {
    		return 1, "good", true, 2
    	} 
    	
    	return 0, "", false, 0
    }

C

type InfoParameters struct {
	A int
	B string
	C bool
	D int
}
type InfoReturns struct {
	AA int
	BB string
	CC bool
	DD int
}
func getInfo3(all InfoParameters) (*InfoReturns) {
       
	if "ok" == "ok" {
		all.A = 1
		all.B = "good"
		all.C = true
		all.D = 2
		return &InfoReturns{all.A,all.B,all.C,all.D }
	}

	return nil
}

提前感谢。


更多关于Golang中哪种"return"写法更好?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复
有趣的问题。[https://tour.golang.org/basics/7](https://tour.golang.org/basics/7) 仅建议对简短函数使用方式A。只有当参数构成"自然"结构体时,才推荐使用方式C,而不仅仅是为了将某些参数组合到函数中。方式A和B的性能应该相当,如果结构体被分配到堆上,方式C可能会稍慢一些。但这种情况是否发生将取决于函数外部的使用方式。

更多关于Golang中哪种"return"写法更好?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


通常应避免使用方案A,除非某个算法使用命名返回值能让代码更优雅。大多数情况下,这种方式反而会造成理解困难。

方案B可以接受,但由于返回参数过多会导致函数难以使用。这个方案我也建议避免。

方案C适用于需要向后兼容的场景(比如后续可能增加返回值,且这是库API的情况)。否则我可能会直接复制结构体而不是返回指针。

我通常不会编写具有这么多返回值的函数,除非在特定上下文中确实有必要。大多数情况下这会造成困惑,特别是当返回值类型各不相同时。

顺便提一下,如果使用命名返回值,可以这样写:

func getInfo() (a string, b err) { return "hello", nil }

也就是说仍然可以像普通函数那样使用return语句。这种方式既能让命名返回值在延迟函数中使用,又能起到文档说明的作用。你会经常看到这种编码风格。

在Go语言中,处理多个返回值时,通常推荐使用命名返回值(如示例A)或结构体封装(如示例C),而不是裸返回多个值(如示例B)。以下是具体分析:

1. 示例A:命名返回值

这种方式通过预定义返回变量,在函数体内直接赋值,并使用裸return语句返回所有值。它提高了代码的可读性,尤其在返回值较多时,能清晰看出每个返回值的含义。

func getInfo(a int, b string, c bool, d int) (aa int, bb string, cc bool, dd int) {
    aa = a + 1       // 直接操作命名返回值
    bb = b + " processed"
    cc = !c
    dd = d * 2
    return           // 裸返回,自动返回aa、bb、cc、dd
}

优点

  • 代码自文档化:从函数签名即可了解返回值用途。
  • 减少错误:避免在return语句中误序或遗漏值。
  • 性能:与示例B相当,Go编译器会优化,无额外开销。

2. 示例B:直接返回多个值

这种方式在return语句中显式列出所有值,适用于返回值较少(如2-3个)的场景,但多个返回值时容易出错。

func getInfo2(a int, b string, c bool, d int) (int, string, bool, int) {
    if condition {
        return 1, "good", true, 2  // 显式返回所有值
    }
    return 0, "", false, 0
}

缺点

  • 可读性差:当返回值增多时,难以快速对应每个值的含义。
  • 维护困难:修改返回值时需确保顺序一致。

3. 示例C:使用结构体封装

当返回值超过3-4个或逻辑复杂时,推荐使用结构体。它通过单一类型聚合数据,简化函数签名,并支持返回指针以减少值复制(尤其在大型结构体时)。

type InfoReturns struct {
    AA int
    BB string
    CC bool
    DD int
}

func getInfo3(params InfoParameters) *InfoReturns {
    if condition {
        return &InfoReturns{
            AA: params.A + 1,
            BB: params.B + " processed",
            CC: !params.C,
            DD: params.D * 2,
        }
    }
    return nil
}

优点

  • 可扩展性:轻松添加新字段,无需修改函数签名。
  • 清晰性:调用方通过字段名访问数据,避免混淆。
  • 性能:返回指针可避免结构体复制,提升效率(但需注意nil情况)。

性能与使用建议

  • 性能:三种方式在性能上无显著差异,Go编译器会进行内联和优化。结构体指针(示例C)在大型数据时可能更高效。
  • 推荐场景
    • 2-3个返回值:使用示例B的直接返回。
    • 多个相关返回值:使用示例A的命名返回值。
    • 复杂数据或需扩展时:使用示例C的结构体。

在实际项目中,示例A示例C更常见,因其提升可维护性。例如,标准库的os.Open返回文件句柄和错误,使用多值返回;而复杂API(如数据库查询)常用结构体封装结果。

回到顶部