Go 的具名返回值:先声明,再往里填

Go 的具名返回值:先声明,再往里填

Jeffery Lv2

函数签名里不但写出返回类型,还给每个返回值起名字。这些名字在函数一进来就已经存在,零值可用,最后可以只写 return


和普通返回差在哪

普通写法:类型在括号里,返回时把值按顺序递出去。

1
2
3
func Depth() ([]*PriceLevel, []*PriceLevel) {
return asks, bids
}

具名写法:每个返回值有名字。这些名字是函数里的局部变量。

1
2
3
4
5
6
func (ob *OrderBook) Depth() (asks, bids []*PriceLevel) {
// asks、bids 已经在,初始是 nil
asks = append(asks, ...)
bids = append(bids, ...)
return // 把当前的 asks、bids 带出去
}

return 后面可以不写东西,叫 naked return(裸返回):把具名变量的当前值原样返回。


进来就是零值

具名返回值在函数开头就分配好了,没赋值也是该类型的零值:切片是 nilerrornildecimal.Decimal 是 0。

所以 processQueue 可以先记下还没吃掉的量,循环里再改:

1
2
3
4
5
6
7
8
9
10
func (ob *OrderBook) processQueue(...) (
done []*Order,
partial *Order,
partialQuantityProcessed, quantityLeft decimal.Decimal,
) {
quantityLeft = quantityToTrade
// done、partial 还没动,分别是 nil
// ...
return
}

调用方仍然按位置接:

1
ordersDone, partialDone, partialProcessed, quantityLeft := ob.processQueue(bestPrice, quantity)

名字只在函数内部当变量用,不影响外面怎么命名。


为什么订单簿爱用它

撮合一次要带回好几样东西:donepartial、已成交量、剩余量、err。具名之后,循环中间可以直接写 done = append(done, ...)partial = ...,最后一行 return 即可。ProcessMarketOrderProcessLimitOrder 都是这个用法。

校验失败时不必用裸返回,按位置写清楚更安全:

1
2
3
if quantity.Sign() <= 0 {
return nil, nil, decimal.Zero, decimal.Zero, ErrInvalidQuantity
}

注意两点

  1. 裸返回在长函数里不好读。 读者要回到签名才能确认带出去的是什么。短函数、或返回值本身就是在攒结果(像 Depth)时最合适。
  2. defer 能改具名返回值。 deferreturn 之后、函数真正退出之前跑,改的是已经填好的那个变量。订单簿里没用这个技巧,知道有这回事即可。

一句话:具名返回值 = 返回槽位提前变成局部变量;return 可以不带参数,把槽位里的值交出去。

  • Title: Go 的具名返回值:先声明,再往里填
  • Author: Jeffery
  • Created at : 2026-09-06 14:40:00
  • Updated at : 2026-09-06 07:11:38
  • Link: https://redefine.ohevan.com/2026/09/06/Go具名返回值/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments
On this page
Go 的具名返回值:先声明,再往里填