Go 變長參數(shù)函數(shù)的實現(xiàn)示例
1. 變長參數(shù)和變長參數(shù)函數(shù)類型
- 一個函數(shù)的最后一個參數(shù)可以是一個變長參數(shù);
- 一個函數(shù)可以最多有一個變長參數(shù);
- 一個變長參數(shù)的類型總為一個切片類型。
變長參數(shù)在聲明的時候必須在它的(切片)類型的元素類型前面前置三個點 ...,以示這是一個變長參數(shù)。 兩個變長函數(shù)類型的例子:
func (values ...int64) (sum int64) func (sep string, tokens ...string) string
2. 變長參數(shù)函數(shù)的聲明
變長函數(shù)聲明和普通函數(shù)聲明類似,只不過最后一個參數(shù)必須為變長參數(shù)。一個變長參數(shù)在函數(shù)體內(nèi)將被視為一個切片。
func Sum(values ...int64) (sum int64) {
// values的類型為[]int64
sum = 0
for _, v := range values {
sum += v
}
return
}
func Concat(sep string, tokens ...string) (r string) {
// tokens的類型為[]string
for i, t := range tokens {
if i != 0 {
r += sep
}
r += t
}
return r
}
從上面的兩個變長參數(shù)函數(shù)聲明可以看出,如果一個變長參數(shù)的類型部分為 ...T,則此變長參數(shù)的類型實際為 []T。
事實上,fmt 標準庫包中的 Print、Println 和 Printf 函數(shù)均為變長參數(shù)函數(shù)。它們的聲明大致如下:
func Print(a ...interface{}) (n int, err error)
func Printf(format string, a ...interface{}) (n int, err error)
func Println(a ...interface{}) (n int, err error)
3. 變長參數(shù)函數(shù)調(diào)用
在變長參數(shù)函數(shù)調(diào)用中,可以使用兩種風格的方式將實參傳遞給類型為 []T 的變長形參:
1.傳遞一個切片做為實參。此切片必須可以被賦值給類型為 []T 的值(或者說此切片可以被隱式轉(zhuǎn)換為類型 []T)。此實參切片后必須跟隨三個點 ...。
2.傳遞零個或者多個可以被隱式轉(zhuǎn)換為 T 的實參(或者說這些實參可以賦值給類型為 T 的值)。 這些實參將被添加入一個匿名的在運行時刻創(chuàng)建的類型為 []T 的切片中,然后此切片將被傳遞給此函數(shù)調(diào)用。
注意,這兩種風格的方式不可在同一個變長參數(shù)函數(shù)調(diào)用中混用。
下面這個例子展示了一些變長參數(shù)函數(shù)調(diào)用:
package main
import "fmt"
func Sum(values ...int64) (sum int64) {
sum = 0
for _, v := range values {
sum += v
}
return
}
func main() {
a0 := Sum()
a1 := Sum(2)
a3 := Sum(2, 3, 5)
// 上面三行和下面三行是等價的。
b0 := Sum([]int64{}...)
b1 := Sum([]int64{2}...)
b3 := Sum([]int64{2, 3, 5}...)
fmt.Println(a0, a1, a3) // 0 2 10
fmt.Println(b0, b1, b3) // 0 2 10
}
4. 模擬實現(xiàn)函數(shù)的可選參數(shù)與默認參數(shù)
來看下 Gin 中的 Run 方法使用:
func (engine *Engine) Run(addr ...string) (err error) {
defer func() { debugPrintError(err) }()
address := resolveAddress(addr)
debugPrint("Listening and serving HTTP on %s\n", address)
err = http.ListenAndServe(address, engine)
return
}
func resolveAddress(addr []string) string {
switch len(addr) {
case 0:
if port := os.Getenv("PORT"); port != "" {
debugPrint("Environment variable PORT="%s"", port)
return ":" + port
}
debugPrint("Environment variable PORT is undefined. Using port :8080 by default")
return ":8080"
case 1:
return addr[0]
default:
panic("too many parameters")
}
}
5. 實現(xiàn)功能選項模式(functional option)
功能選項模式使得我們在設(shè)計和實現(xiàn)帶有配置選項的函數(shù)或方法時,更靈活優(yōu)雅:
package main
import "fmt"
type CoffeeOptions struct {
sugar int
milk int
coffeePowder int
}
// 這個函數(shù)會接受上面結(jié)構(gòu)體 CoffeeOptions 實例的指針 這個函數(shù)最終的目的都是為了修改實例
type CoffeeOption func(*CoffeeOptions)
// 下面這三個函數(shù)都會返回 CoffeeOption 函數(shù) 方便修改 CoffeeOptions 結(jié)構(gòu)體
func CoffeeSugar(sugar int) CoffeeOption {
return func(opts *CoffeeOptions) {
opts.sugar = sugar
}
}
func CoffeeMilk(milk int) CoffeeOption {
return func(opts *CoffeeOptions) {
opts.milk = milk
}
}
func CoffeePowder(coffeePowder int) CoffeeOption {
return func(opts *CoffeeOptions) {
opts.coffeePowder = coffeePowder
}
}
func newDefaultCoffeeOptions() *CoffeeOptions {
return &CoffeeOptions{
sugar: 5,
milk: 0,
coffeePowder: 60,
}
}
func NewCoffee(opts ...CoffeeOption) *CoffeeOptions {
// 新建實例opt
defaultOptions := newDefaultCoffeeOptions()
// 根據(jù)所傳的參數(shù)修改opt實例
for _, o := range opts {
o(defaultOptions)
}
return defaultOptions
}
func main() {
// 創(chuàng)建函數(shù)來修改實例
opts := NewCoffee(
CoffeeSugar(10),
CoffeeMilk(10),
CoffeePowder(80),
)
fmt.Printf("%#v", *opts)
// main.CoffeeOptions{sugar:10, milk:10, coffeePowder:80}
}在 go-micro 中你可以看到很多 functional option 的應(yīng)用,基本每個 micro 組件都使用了這種方式進行構(gòu)造。
到此這篇關(guān)于Go 變長參數(shù)函數(shù)的實現(xiàn)示例的文章就介紹到這了,更多相關(guān)Go 變長參數(shù)函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Golang標準庫os/exec執(zhí)行外部命令并獲取其輸出包代碼示例
這篇文章主要為大家介紹了Golang標準庫os/exec執(zhí)行外部命令并獲取其輸出包代碼示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-12-12
關(guān)于golang?struct?中的?slice?無法原子賦值的問題
這篇文章主要介紹了為什么?golang?struct?中的?slice?無法原子賦值的問題,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2024-01-01

