最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go進(jìn)階之長(zhǎng)參數(shù)函數(shù)的實(shí)現(xiàn)

 更新時(shí)間:2026年06月05日 09:50:33   作者:念何架構(gòu)之路  
本文主要介紹了Go語(yǔ)言中變長(zhǎng)參數(shù)函數(shù)的使用方法和應(yīng)用場(chǎng)景,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

在Go中.變長(zhǎng)參數(shù)函數(shù)使用的最多的就是fmt包 log包中的幾個(gè)導(dǎo)出函數(shù).

源碼位置:src/fmt/print.go

// Println formats using the default formats for its operands and writes to standard output.
// Spaces are always added between operands and a newline is appended.
// It returns the number of bytes written and any write error encountered.
func Println(a ...any) (n int, err error) {
	return Fprintln(os.Stdout, a...)
}



// Printf formats according to a format specifier and writes to standard output.
// It returns the number of bytes written and any write error encountered.
func Printf(format string, a ...any) (n int, err error) {
	return Fprintf(os.Stdout, format, a...)
}

源碼位置:src/log/log.go

// Printf calls l.Output to print to the logger.
// Arguments are handled in the manner of [fmt.Printf].
func (l *Logger) Printf(format string, v ...any) {
	l.output(0, 2, func(b []byte) []byte {
		return fmt.Appendf(b, format, v...)
	})
}

// Println calls l.Output to print to the logger.
// Arguments are handled in the manner of [fmt.Println].
func (l *Logger) Println(v ...any) {
	l.output(0, 2, func(b []byte) []byte {
		return fmt.Appendln(b, v...)
	})
}

1.變長(zhǎng)參數(shù)函數(shù):

變長(zhǎng)參數(shù)就是指調(diào)用時(shí)可以接受零個(gè) 一個(gè)或多個(gè)實(shí)際參數(shù)的函數(shù).示例如下:

可以看到無(wú)論傳入零個(gè) 兩個(gè)還是多個(gè)實(shí)際參數(shù).都傳給了Print()方法的形式參數(shù)a(參考上面源碼).形參a的類型是...any.這種接受"...T"類型形式參數(shù)的函數(shù)就被稱為變長(zhǎng)參數(shù)函數(shù).一個(gè)變長(zhǎng)參數(shù)函數(shù)只能有一個(gè)"...T"類型形式參數(shù).并且該形式參數(shù)應(yīng)該為函數(shù)參數(shù)列表中的最后一個(gè)形式參數(shù).否則Go編譯器會(huì)有錯(cuò)誤提示.

變長(zhǎng)參數(shù)函數(shù)的"...T"類型形式參數(shù)在函數(shù)體內(nèi)呈現(xiàn)為[]T類型的變量.可以將其理解為一個(gè)Go的語(yǔ)法糖.示例如下:

func sum(arg ...int) int {
	var total int 
	//arg的類型為[]int
	for _, v := range arg {
		total += v
	}
	return total
}

在函數(shù)外部."...T"類型形式參數(shù)可以匹配和接受的實(shí)參類型有兩種.

1).多個(gè)T類型變量.

2).t...(t為[]T類型變量).示例如下:

func main() {
	a, b, c := 1, 2, 3
	fmt.Println(sum(a, b, c))

	nums := []int{1, 2, 3}
	fmt.Println(sum(nums...))
}

func sum(arg ...int) int {
	var total int
	//arg的類型為[]int
	for _, v := range arg {
		total += v
	}
	return total
}

我們只能選擇上述兩種實(shí)參類型的一種.要么是多個(gè)T類型變量.要么是t...(t為[]T類型變量).如果兩種混用.會(huì)得到類似下面的編譯錯(cuò)誤.

使用變長(zhǎng)參數(shù)函數(shù)最容易出現(xiàn)的問(wèn)題是實(shí)參與形參不匹配.示例如下:

func main() {
	s := []string{"a", "b", "c"}
	dump(s...)
}

func dump(args ...interface{}) {
	for _, v := range args {
		fmt.Println(v)
	}
}

編譯器給出了類型不匹配的錯(cuò)誤.雖然string類型可以直接賦值給interface{}類型變量.但是[]string類型變量并不能直接賦值給[]interface{}類型變量.修改示例如下:

func main() {
	s := []interface{}{"a", "b", "c"}
	dump(s...)
}

func dump(args ...interface{}) {
	for _, v := range args {
		fmt.Println(v)
	}
}

不過(guò)有個(gè)例外.就是Go的內(nèi)置函數(shù)append函數(shù).它支持通過(guò)下面的方式將字符串附加到一個(gè)字節(jié)后面.示例如下:

func main() {
	b := []byte{}
	b = append(b, "hello"...)
	fmt.Println(b)
}

string類型本身不滿足類型要求(append本需要[]byte...).這算是Go的一個(gè)編譯優(yōu)化.編譯器自動(dòng)將string隱式轉(zhuǎn)換為了[]byte.

func main() {
	b := []byte{}
	b = append(b, "hello"...)
	fmt.Println(b)
	
	fooTest(b)
}

func fooTest(b ...byte) {
	fmt.Println(b)
}

2.模擬函數(shù)重載:

Go語(yǔ)言不允許在同一個(gè)作用域下定義名字相同但函數(shù)原型不同的函數(shù).如果

定義這樣的函數(shù).Go編譯器會(huì)提示下面代碼的錯(cuò)誤信息.

func concat(a, b int) string {
	return fmt.Sprintf("%d %d", a, b)
}

func concat(x, y string) string {
	return fmt.Sprintf("%s %s", x, y)
}

func concat(s []string)string  {
	return strings.Join(s, " ")
}

要修復(fù)上面的錯(cuò)誤.只能修改函數(shù)命名.但是在其他語(yǔ)言中.比如java.就支持這種名字相同.參數(shù)類型不同的重載函數(shù).但Go語(yǔ)言并不支持函數(shù)重載.Go語(yǔ)言官方給出不支持的理由是:其他語(yǔ)言的經(jīng)驗(yàn)告訴我們.使用具有相同名稱但是函數(shù)簽名不同的多種方法有時(shí)會(huì)很有用.但在實(shí)踐中也可能會(huì)造成混淆和脆弱性.在Go的類型系統(tǒng)中.僅按名稱進(jìn)行匹配要求類型一致是一個(gè)主要的簡(jiǎn)化決策.變長(zhǎng)參數(shù)解決.示例如下:

func main() {
	fmt.Println(concat("-", 1, 2))
	fmt.Println(concat("-", "hello", "gopher"))

}

func concat(sep string, args ...interface{}) string {
	var result string
	for i, v := range args {
		if i != 0 {
			result += sep
		}
		switch v.(type) {
		case int, int8, int16, int32, int64,
			uint, uint8, uint16, uint32, uint64:
			result += fmt.Sprintf("%v", v)
		case string:
			result += fmt.Sprintf("%s", v)
		case []int:
			ints := v.([]int)
			for i, v := range ints {
				if i != 0 {
					result += sep
				}
				result += fmt.Sprintf("%v", v)
			}
		case []string:
			strings := v.([]string)
			result += fmt.Sprintf("%v", strings)
		default:
			fmt.Println("不支持此類型")
			return ""
		}
	}
	return result
}

3.模擬實(shí)現(xiàn)函數(shù)的可選參數(shù)和默認(rèn)參數(shù):

如果參數(shù)在傳入時(shí)有隱式要求的固定順序(調(diào)用者保證).還可以利用變長(zhǎng)參數(shù)函數(shù)模擬實(shí)現(xiàn)可選參數(shù)和默認(rèn)參數(shù).示例如下:

type record struct {
	name    string
	gender  string
	age     int
	city    string
	country string
}

func enroll(args ...interface{}) (*record, error) {
	if len(args) > 5 || len(args) < 3 {
		return nil, fmt.Errorf("the number of arguments passed to wrong")
	}

	r := &record{
		city:    "ShanXi",
		country: "TaiYuan",
	}

	for i, v := range args {
		switch i {
		case 0:
			name, ok := v.(string)
			if !ok {
				return nil, fmt.Errorf("the first argument to enroll must be a string")
			}
			r.name = name
		case 1:
			gender, ok := v.(string)
			if !ok {
				return nil, fmt.Errorf("the second argument to enroll must be a string")
			}
			r.gender = gender
		case 2:
			age, ok := v.(int)
			if !ok {
				return nil, fmt.Errorf("the third argument to enroll must be an uint16")
			}
			r.age = age
		case 3:
			city, ok := v.(string)
			if !ok {
				return nil, fmt.Errorf("the third argument to enroll must be a string")
			}
			r.city = city
		case 4:
			country, ok := v.(string)
			if !ok {
				return nil, fmt.Errorf("the fourth argument to enroll must be a string")
			}
			r.country = country
		default:
			return nil, fmt.Errorf("unknown argument %d", i)
		}
	}
	return r, nil

}

func main() {
	r, _ := enroll("小明", "male", 26)
	fmt.Printf("%+v\n", *r)

	r1, _ := enroll("小明", "male", 26, "linfen")
	fmt.Printf("%+v\n", *r1)

}

4.實(shí)現(xiàn)功能選項(xiàng):

1).通過(guò)參數(shù)暴露配置選項(xiàng):

type FinishedHouse struct {
	style                  int
	centralAirConditioning bool
	floorMaterial          string
	wallMaterial           string
}

func NewFinishedHouse(style int, centralAirConditioning bool, floorMaterial, wallMaterial string) *FinishedHouse {
	h := &FinishedHouse{
		style:                  style,
		centralAirConditioning: centralAirConditioning,
		floorMaterial:          floorMaterial,
		wallMaterial:           wallMaterial,
	}
	return h
}

func main() {
	fmt.Printf("%+v\n", NewFinishedHouse(0, true, "wood", "paper"))
}

上面設(shè)計(jì)的唯一優(yōu)點(diǎn)就是快速實(shí)現(xiàn).不足之處很多.最致命的是接口無(wú)法擴(kuò)展.

2)結(jié)構(gòu)體封裝配置項(xiàng):

type FinishedHouse struct {
	style                  int
	centralAirConditioning bool
	floorMaterial          string
	wallMaterial           string
}

type Options struct {
	style                  int
	centralAirConditioning bool
	floorMaterial          string
	wallMaterial           string
}

func NewFinishedHouse(options *Options) *FinishedHouse {
	var style  = 0
	var centralAirConditioning = true
	var floorMaterial = "wood"
	var wallMaterial = "paper"
	if options != nil {
		style = options.style
		centralAirConditioning = options.centralAirConditioning
		floorMaterial = options.floorMaterial
		wallMaterial = options.wallMaterial
	}
	h := &FinishedHouse{
		style:                  style,
		centralAirConditioning: centralAirConditioning,
		floorMaterial:          floorMaterial,
		wallMaterial:           wallMaterial,
	}
	return h
}

func main() {
	fmt.Printf("%+v\n", NewFinishedHouse(0, true, "wood", "paper"))
}

優(yōu)點(diǎn):

1).后續(xù)添加配置項(xiàng)選項(xiàng).Options結(jié)構(gòu)體可以隨著時(shí)間變遷而增長(zhǎng).但FinishedHouse創(chuàng)建函數(shù)本身的Api簽名不變.

2).允許調(diào)用者使用nil來(lái)表示他們希望使用默認(rèn)值來(lái)創(chuàng)建.

3).可以更好地記錄文檔.

缺點(diǎn):

1).每次都要為Options中所有字段賦值.

2).如果Options中的值在調(diào)用后變化了怎么辦.

3).使用功能選項(xiàng):

type FinishedHouse struct {
	style                  int
	centralAirConditioning bool
	floorMaterial          string
	wallMaterial           string
}

type Option func(h *FinishedHouse)

func NewFinishedHouse(options ...Option) *FinishedHouse {
	h := &FinishedHouse{
		style:                  0,
		centralAirConditioning: true,
		floorMaterial:          "wood",
		wallMaterial:           "paper",
	}

	for _, option := range options {
		option(h)
	}

	return h
}

func WithStyle(style int) Option {
	return func(h *FinishedHouse) {
		h.style = style
	}
}

func WithCentralAirConditioning(centralAirConditioning bool) Option {
	return func(h *FinishedHouse) {
		h.centralAirConditioning = centralAirConditioning
	}
}

func WithFloorMaterial(floorMaterial string) Option {
	return func(h *FinishedHouse) {
		h.floorMaterial = floorMaterial
	}
}

func WithWallMaterial(wallMaterial string) Option {
	return func(h *FinishedHouse) {
		h.floorMaterial = wallMaterial
	}
}

func main() {
	//默認(rèn).
	fmt.Printf("%+v\n", NewFinishedHouse())

	fmt.Printf("%+v\n", NewFinishedHouse(WithStyle(1), WithFloorMaterial("title")))

}

到此這篇關(guān)于Go進(jìn)階之長(zhǎng)參數(shù)函數(shù)的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Go 長(zhǎng)參數(shù)函數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go遞歸修改文件名的實(shí)例代碼

    Go遞歸修改文件名的實(shí)例代碼

    這篇文章主要介紹了Go遞歸修改文件名的實(shí)例代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的餓參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • 多階段構(gòu)建優(yōu)化Go?程序Docker鏡像

    多階段構(gòu)建優(yōu)化Go?程序Docker鏡像

    這篇文章主要為大家介紹了多階段構(gòu)建優(yōu)化Go?程序Docker鏡像,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • 淺析Go使用定時(shí)器時(shí)如何避免潛在的內(nèi)存泄漏陷阱

    淺析Go使用定時(shí)器時(shí)如何避免潛在的內(nèi)存泄漏陷阱

    這篇文章來(lái)和大家一起探討一下Go?中如何高效使用?timer,特別是與select?一起使用時(shí),如何防止?jié)撛诘膬?nèi)存泄漏問(wèn)題,感興趣的可以了解下
    2024-01-01
  • golang程序打包成腳本部署到Linux系統(tǒng)方式

    golang程序打包成腳本部署到Linux系統(tǒng)方式

    Golang程序通過(guò)本地編譯(設(shè)置GOOS為linux生成無(wú)后綴二進(jìn)制文件),上傳至Linux服務(wù)器后賦權(quán)執(zhí)行,使用nohup命令實(shí)現(xiàn)后臺(tái)運(yùn)行,完成自動(dòng)化部署
    2025-07-07
  • go語(yǔ)言解決并發(fā)問(wèn)題小結(jié)

    go語(yǔ)言解決并發(fā)問(wèn)題小結(jié)

    并發(fā)是GO最基本的功能了,但是在傳統(tǒng)的PHP中是比較困難的,如果不借助其它一些擴(kuò)展的話,是做不到并發(fā)的,這篇文章主要介紹了go語(yǔ)言如何解決并發(fā)問(wèn)題,需要的朋友可以參考下
    2024-05-05
  • Go語(yǔ)言中利用http發(fā)起Get和Post請(qǐng)求的方法示例

    Go語(yǔ)言中利用http發(fā)起Get和Post請(qǐng)求的方法示例

    這篇文章主要給大家介紹了關(guān)于Go語(yǔ)言中利用http發(fā)起Get和Post請(qǐng)求的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-11-11
  • 詳解Golang的GC三色標(biāo)記法

    詳解Golang的GC三色標(biāo)記法

    這篇文章主要為大家介紹了Golang的GC三色標(biāo)記法,文中有詳細(xì)的實(shí)現(xiàn)過(guò)程供大家參考,對(duì)大家的學(xué)習(xí)或工作有一定幫助,感興趣的可以跟著小編一來(lái)看看
    2023-05-05
  • GO語(yǔ)言開(kāi)發(fā)終端命令行小工具改進(jìn)更新

    GO語(yǔ)言開(kāi)發(fā)終端命令行小工具改進(jìn)更新

    這篇文章主要為大家介紹了GO語(yǔ)言開(kāi)發(fā)終端命令行小工具的改進(jìn)更新,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • Go語(yǔ)言使用Swiss Table實(shí)現(xiàn)更快的map

    Go語(yǔ)言使用Swiss Table實(shí)現(xiàn)更快的map

    wiss Table 是一種高效的哈希表實(shí)現(xiàn),最初由 Google 在 C++ 中引入,后來(lái)也被其他語(yǔ)言(如 Rust)采用,下面我們看看如何使用 Swiss Table 的思想來(lái)實(shí)現(xiàn)一個(gè)更快的 Go map
    2025-03-03
  • golang的Pseudo-versions使用問(wèn)題解析

    golang的Pseudo-versions使用問(wèn)題解析

    這篇文章主要為大家介紹有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪了golang的Pseudo-versions使用問(wèn)題解析,
    2023-07-07

最新評(píng)論

遂平县| 蓬莱市| 出国| 阳泉市| 巧家县| 宝兴县| 北宁市| 荣昌县| 湟中县| 顺平县| 霸州市| 五台县| 翁牛特旗| 平塘县| 四会市| 惠水县| 扎赉特旗| 美姑县| 石狮市| 陇南市| 科技| 阳春市| 南皮县| 黎城县| 桑植县| 铜山县| 永昌县| 六盘水市| 阳信县| 任丘市| 宣城市| 阳曲县| 射阳县| 古丈县| 伊通| 中江县| 伊宁县| 通化县| 类乌齐县| 晴隆县| 府谷县|