【golang】實現數組 map 方法

【golang】實現數組 map 方法

經常會在項目裏用到數組的 map 方法,閒來無事打算在 golang 中實現一下 map 方法。上工具要先上用法

numbers := []int{1, 2, 3}

// convert to []interface{}
interfaceNumbers, err := utils.ToInterface(numbers)

utils.Check(err)

dup := utils.Map(interfaceNumbers, func(item interface{}) interface{} {
		v, ok := item.(int)

		if !ok {
			utils.Check(fmt.Errorf("assert error"))
		}

		return v + 1
})

fmt.Println(dup) // [ 2, 3, 4 ]

其實跟其他支持函數式的語言無異,只是多了個類型斷言,這是有點麻煩也迫不得已的地方,先別急,實現會放到下面。

首先要捋清思路的是,map 的第一個參數是傳遞目標切片,當然切片可以是任意類型的切片,但是有點頭疼的是 Golang 中並沒有泛型,所以這裏只能用 []interface{},這樣導致的結果是傳遞參數之前是有確切類型聲明的,但是出來的時候就是 []interface{} 還得在外面再做一層斷言。

先來看一下 map 函數的具體實現

func Map(slice  []interface{}, cb func(interface{}) interface{}) []interface{} {
	dup := make([]interface{}, len(slice))

	copy(dup, slice)

	for index, val := range slice  {
		dup[index] = cb(val)
	}

	return dup
}

實現比較簡單,只是將傳遞進來的回調在內部執行傳遞切片的每個項,這裏爲了避免副作用,在內部重新創建了一個新的切片,通過 copy 方法把舊切片的值拷貝到新的切片當中。

重要的是 map 的函數簽名,傳遞一個 slicecb 返回一個 []interface{},值得關注的是 slice 的類型,slice 的類型爲 []interface{} ,看起來是沒有問題的,但是如果你傳遞一個其他的類型的切片就會拋出 panic,這是因爲 golang 會認爲它們是兩種不同的類型,儘管 interface{} 是可以兼容任何類型,但是 []interface{} 是一種新的類型,它是一種能夠容納任何類型的切片,它並不兼容任何類型的切片,詳情戳

這裏就不再贅述了。

所以我們還要實現一個能夠把任意切片轉換爲 []interface{} 的一個轉換函數,思路是利用反射判斷類型,然後將它 copy 成一個新的切片並返回

func ToInterface(slice interface{}) ([]interface{}, error) {
	v := reflect.ValueOf(slice)

	if v.Kind() != reflect.Slice {
			return nil, fmt.Errorf("argument must be a slice")
	}

	r := make([]interface{}, v.Len())

	for i := 0; i < v.Len(); i++ {
		r[i] = v.Index(i).Interface()
	}

	return r, nil
}

ToInterface 利用反射檢測類型是否正確,如果不是切片,則拋出一個 error。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章