日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Go Little Book - 第三章 - 字典 ,数组和切片

發布時間:2025/3/17 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Go Little Book - 第三章 - 字典 ,数组和切片 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

2019獨角獸企業重金招聘Python工程師標準>>>

第三章 - 字典 ,數組和切片(Chapter 3 - Maps, Arrays and Slices)

So far we've seen a number of simple types and structures. It's now time to look at arrays, slices and maps.

目前為止我們看了些簡單類型和結構體。現在是時候來看看數組,切片和字典了。

數組(Arrays)

If you come from Python, Ruby, Perl, JavaScript or PHP (and more), you're probably used to programming with dynamic arrays. These are arrays that resize themselves as data is added to them. In Go, like many other languages, arrays are fixed. Declaring an array requires that we specify the size, and once the size is specified, it cannot grow:

如果你從Python、Ruby、Perl、JavaScript或者PHP(還有更多),你可能使用過動態數組。這些數組當數據添加進來可以調整大小。在Go中,和其他語言一樣,數組是固定大小的。申請一個數組需要我們指定它的大小。申明一個數組時需要指定大小,一旦大小指定了,就不能增長了:

var scores [10]int scores[0] = 339

The above array can hold up to 10 scores using indexes scores[0] through scores[9]. Attempts to access an out of range index in the array will result in a compiler or runtime error.

上面的這個數組從scores[0]到scores[9]可以容納10個分數。嘗試訪問超出數組索引的會報編譯或者運行時錯誤。

We can initialize the array with values:

我們可以帶值初始化數組:

scores := [4]int{9001, 9333, 212, 33}

We can use len to get the length of the array. range can be used to iterate over it:

我們可能通過len來獲取數組的長度??梢杂胷ange來迭代數組。

for index, value := range scores {}

Arrays are efficient but rigid. We often don't know the number of elements we'll be dealing with upfront. For this, we turn to slices.

數組高效但不靈活。我們常常不能預先知道有多少元素需要處理。因此,我們使用切片。

切片(Slices)

In Go, you rarely, if ever, use arrays directly. Instead, you use slices. A slice is a lightweight structure that wraps and represents a portion of an array. There are a few ways to create a slice, and we'll go over when to use which later on. The first is a slight variation on how we created an array:

在Go中,你很少,或者根本不,直接使用數組。反而,你使用切片。切片是對數組一個輕量型封裝。有幾種方式來創建一個切片,我們會全部過一遍。第一種方式和創建數組有一點小小的變化。

scores := []int{1,4,293,4,9}

Unlike the array declaration, our slice isn't declared with a length within the square brackets. To understand how the two are different, let's see another way to create a slice, using make:

和申請數組不同,我們的切片沒有在中括號內指定長度。要理解這兩者的不同,我們用另一種方式創建切片,使用make:

scores := make([]int, 10)

We use make instead of new because there's more to creating a slice than just allocating the memory (which is what new does). Specifically, we have to allocate the memory for the underlying array and also initialize the slice. In the above, we initialize a slice with a length of 10 and a capacity of 10. The length is the size of the slice, the capacity is the size of the underlying array. Using make we can specify the two separately:

我們使用make來替代new因為創建一個切片比只是分配內存(new做的事情)要復雜一些。特別的,我們需要分配底層數組和初始化切片。上面的例子,我們初始化了一個長度和容量為10的切片。長度是切片的大小,容量時底層數組的大小。使用make時可以分開提定這兩個值:

scores := make([]int, 0, 10)

This creates a slice with a length of 0 but with a capacity of 10. (If you're paying attention, you'll note that make and len are overloaded. Go is a language that, to the frustration of some, makes use of features which aren't exposed for developers to use.)

這創建了一個長度為0但容量為10的切片。(如果你留心,你會注意到make和len是重載的。Go有的時候令人沮喪,一些在使用的功能沒有暴露給開發者使用。)

To better understand the interplay between length and capacity, let's look at some examples:

為了更好的理解長度和容量之間的相互作用,讓我們來看一個例子:

func main() {scores := make([]int, 0, 10)scores[5] = 9033fmt.Println(scores) }

Our first example crashes. Why? Because our slice has a length of 0. Yes, the underlying array has 10 elements, but we need to explicitly expand our slice in order to access those elements. One way to expand a slice is via append:

我們的第一個程序崩潰了。為什么呢?因我們的切片的長度為0。是的,底層數組有10個元素,但是我們需要顯示的擴展切片來訪問這些元素。一種擴展方式是使用append:

func main() {scores := make([]int, 0, 10)scores = append(scores, 5)fmt.Println(scores) // prints [5] }

But that changes the intent of our original code. Appending to a slice of length 0 will set the first element. For whatever reason, our crashing code wanted to set the element at index 5. To do this, we can re-slice our slice:

上面的修改改變了我們的原始代碼的意圖。擴展一個長度為0的切片會設置第一個元素。無論什么原因,我們崩潰的代碼想要的是修改索引為5的元素。 我們可以重切片一次我們的切片:

func main() {scores := make([]int, 0, 10)scores = scores[0:6]scores[5] = 9033fmt.Println(scores) }

How large can we resize a slice? Up to its capacity which, in this case, is 10. You might be thinking this doesn't actually solve the fixed-length issue of arrays. It turns out that append is pretty special. If the underlying array is full, it will create a new larger array and copy the values over (this is exactly how dynamic arrays work in PHP, Python, Ruby, JavaScript, ...). This is why, in the example above that used append, we had to re-assign the value returned by append to our scores variable: append might have created a new value if the original had no more space.

我們調整切片最大是多少?這是由它的容量決定的,在本例中,是10。你可能會想這沒有從本質上解決數能固定和長度的問題。事實上,append是非常特殊的。當底層數組滿了,它會創建一個新的數組,并把數值拷貝過來(PHP, Python, Ruby, JavaScript等也是這么做的)。這也就是為什么,我們上面的代碼,使用了append之后,我們需要把append的返回值重新賦值給scores的原因:append會產生一個新的值如果原始的空間不足。

If I told you that Go grew arrays with a 2x algorithm, can you guess what the following will output?

如果我告訴你說Go是近兩倍的算法來增長數組,那下面的代碼會輸出什么?

func main() {scores := make([]int, 0, 5)c := cap(scores)fmt.Println(c)for i := 0; i < 25; i++ {scores = append(scores, i)// if our capacity has changed,// Go had to grow our array to accommodate the new dataif cap(scores) != c {c = cap(scores)fmt.Println(c)}} }

The initial capacity of scores is 5. In order to hold 20 values, it'll have to be expanded 3 times with a capacity of 10, 20 and finally 40.

scores最初的容量是5。為了容納20個值,它將會擴展3次,分別是10,20和40。

As a final example, consider:

來思考下最后一個例子:

func main() {scores := make([]int, 5)scores = append(scores, 9332)fmt.Println(scores) }

Here, the output is going to be [0, 0, 0, 0, 0, 9332]. Maybe you thought it would be [9332, 0, 0, 0, 0]? To a human, that might seem logical. To a compiler, you're telling it to append a value to a slice that already holds 5 values.

這里,輸出是[0, 0, 0, 0, 0, 9332]。可能你會想它應該是[9332, 0, 0, 0, 0]?對于人來說這可能符合邏輯。對于編譯器來說,你告訴它的就是要擴展一個已經有5個值的切片。

Ultimately, there are four common ways to initialize a slice:

最后,有四種常用的方式來初始化一個切片:

names := []string{"leto", "jessica", "paul"} checks := make([]bool, 10) var names []string scores := make([]int, 0, 20)

When do you use which? The first one shouldn't need much of an explanation. You use this when you know the values that you want in the array ahead of time.

何時用哪一種呢?第一種不需要過多的解釋。當你知道所有的值并且你要的是數組頭的時候使用。

The second one is useful when you'll be writing into specific indexes of a slice. For example:

當你需要寫入切片的指定索引時,第二種就很有用。比如:

func extractPowers(saiyans []*Saiyans) []int {powers := make([]int, len(saiyans))for index, saiyan := range saiyans {powers[index] = saiyan.Power}return powers }

The third version is a nil slice and is used in conjunction with append, when the number of elements is unknown.

當知道有多少元素的時候,就可使用第三種是一個空切片和append配合使用。

The last version lets us specify an initial capacity; useful if we have a general idea of how many elements we'll need.

當我們對需要多少元素有多少了解時使用最后一種方式來指定初始容量。

Even when you know the size, append can be used. It's largely a matter of preference:

即使你知道了大小,append依然可以使用。這很大程度上是一個偏好問題:

func extractPowers(saiyans []*Saiyans) []int {powers := make([]int, 0, len(saiyans))for _, saiyan := range saiyans {powers = append(powers, saiyan.Power)}return powers }

Slices as wrappers to arrays is a powerful concept. Many languages have the concept of slicing an array. Both JavaScript and Ruby arrays have a slice method. You can also get a slice in Ruby by using [START..END] or in Python via [START:END]. However, in these languages, a slice is actually a new array with the values of the original copied over. If we take Ruby, what's the output of the following?

切片做為數組的封裝是一個很有用的概念。許多語言有數組切片的概念。JavaScript和Ruby的數組都有slice方法。你可以對通過[START..END]或者在Python中用[START:END]的方式取得一個切片。但是,在這些語言中切片是對原數組的拷貝。如果我們使用Ruby,下面的代碼會輸出什么?

scores = [1,2,3,4,5] slice = scores[2..4] slice[0] = 999 puts scores

The answer is [1, 2, 3, 4, 5]. That's because slice is a completely new array with copies of values. Now, consider the Go equivalent:

答案是[1, 2, 3, 4, 5]。那是因為slice是一個復制了所有值的全新數組?,F在,來看下Go相同的代碼:

scores := []int{1,2,3,4,5} slice := scores[2:4] slice[0] = 999 fmt.Println(scores)

The output is [1, 2, 999, 4, 5].

輸出是[1, 2, 999, 4, 5]。

This changes how you code. For example, a number of functions take a position parameter. In JavaScript, if we want to find the first space in a string (yes, slices work on strings too!) after the first five characters, we'd write:

這改變了你的編碼方式。比如,一些函數需要一個位置參數。在JavaScript中,如果我們需要找到字符串中第五個字符之后的第一個空格(是的,切片對字符串也是有效的!), 我們這樣寫:

haystack = "the spice must flow"; console.log(haystack.indexOf(" ", 5));

In Go, we leverage slices:

在Go中,我們使用切片:

strings.Index(haystack[5:], " ")

We can see from the above example, that [X:] is shorthand for from X to the end while [:X] is shorthand for from the start to X. Unlike other languages, Go doesn't support negative values. If we want all of the values of a slice except the last, we do:

上面的例子,我們可以看到,[X:]是從X到結束的簡寫,就如[:X]是從開始到X的簡寫一樣。和其他語言不同的是,Go不支持反向取值(這邊感覺不對)。如果我們需要切片除了最后一個值以外的所有值,我們這樣來寫:

scores := []int{1, 2, 3, 4, 5} scores = scores[:len(scores)-1]

The above is the start of an efficient way to remove a value from an unsorted slice:

以上是一種快速刪除未排序的切片中的某個值的方法的開頭:

func main() {scores := []int{1, 2, 3, 4, 5}scores = removeAtIndex(scores, 2)fmt.Println(scores) }func removeAtIndex(source []int, index int) []int {lastIndex := len(source) - 1//swap the last value and the value we want to removesource[index], source[lastIndex] = source[lastIndex], source[index]return source[:lastIndex] }

Finally, now that we know about slices, we can look at another commonly used built-in function: copy. copy is one of those functions that highlights how slices change the way we code. Normally, a method that copies values from one array to another has 5 parameters: source, sourceStart, count, destination and destinationStart. With slices, we only need two:

最后,既然我們是學習了切片,我們來看另一個常用的內置函數: copy。 copy是能突出切片是如何改變我們的編碼方式的函數之一。通常,數組間拷貝需要5個參數:source, sourceStart, count, destination 和 destinationStart。使用切片只要兩個:

import ("fmt""math/rand""sort" )func main() {scores := make([]int, 100)for i := 0; i < 100; i++ {scores[i] = int(rand.Int31n(1000))}sort.Ints(scores)worst := make([]int, 5)copy(worst, scores[:5])fmt.Println(worst) }

Take some time and play with the above code. Try variations. See what happens if you change copy to something like copy(worst[2:4], scores[:5]), or what if you try to copy more or less than 5 values into worst?

花一些時間來執行上面的代碼。多試幾次。看看會發生什么,如果將代碼改為copy(worst[2:4], scores[:5]),或者要拷貝比5更多或少的值到worst?

映射(Maps)

Maps in Go are what other languages call hashtables or dictionaries. They work as you expect: you define a key and value, and can get, set and delete values from it.

Go中的映射在其他語言中叫哈希表或者字典。它們都如你想的一樣:你定義一個鍵和值,然后你可以通過映射來刪改查這些值。

Maps, like slices, are created with the make function. Let's look at an example:

映射,和切片一樣,是通過make函數來創建的。讓我們來看一個例子:

func main() {lookup := make(map[string]int)lookup["goku"] = 9001power, exists := lookup["vegeta"]// prints 0, false// 0 is the default value for an integerfmt.Println(power, exists) }

To get the number of keys, we use len. To remove a value based on its key, we use delete:

我們使用len來獲取有多少鍵。要通過鍵來刪除一個值,我們用delete:

// returns 1 total := len(lookup)// has no return, can be called on a non-existing key delete(lookup, "goku")

Maps grow dynamically. However, we can supply a second argument to make to set an initial size:

映射是動態增長的。但是,我們可以通過make的第二個參數來設置它的初始大小:

lookup := make(map[string]int, 100)

If you have some idea of how many keys your map will have, defining an initial size can help with performance.

如果知道有多少值,指定初始大小可以有更好的性能表現。

When you need a map as a field of a structure, you define it as:

如果想要把映射做為結構體的一個字段,我們這樣定義:

type Saiyan struct {Name stringFriends map[string]*Saiyan }

One way to initialize the above is via:

初始化的一種方式:

goku := &Saiyan{Name: "Goku",Friends: make(map[string]*Saiyan), } goku.Friends["krillin"] = ... //todo load or create Krillin

There's yet another way to declare and initialize values in Go. Like make, this approach is specific to maps and arrays. We can declare as a composite literal:

在Go中有另一種申明和初始化的方式。和make一樣,這對映射和數組都是有效的。我們可以像組合文字一樣申明:

lookup := map[string]int{"goku": 9001,"gohan": 2044, }

We can iterate over a map using a for loop combined with the range keyword:

我們可以通過for和range關鍵字來迭代映射:

for key, value := range lookup {... }

Iteration over maps isn't ordered. Each iteration over a lookup will return the key value pair in a random order.

映射的迭代器是無序的。每個迭代器隨機查找鍵值對。

指針和值(Pointers versus Values)

We finished Chapter 2 by looking at whether you should assign and pass pointers or values. We'll now have this same conversation with respect to array and map values. Which of these should you use?

通過了解什么時候傳值或指針我們結束了第二章。在數組和映射的值方面我們將碰到相同的問題。我們應該用哪一種?

a := make([]Saiyan, 10) //or b := make([]*Saiyan, 10)

Many developers think that passing b to, or returning it from, a function is going to be more efficient. However, what's being passed/returned is a copy of the slice, which itself is a reference. So with respect to passing/returning the slice itself, there's no difference.

許多開發人員會想對于一個函數來說是傳b還是將它做為返回值更高效。然而,這里傳遞或者返回的都是一個切片的拷貝,它本身就是一個引用。所以就傳遞或者返回這個切片而言,沒有什么區別。

Where you will see a difference is when you modify the values of a slice or map. At this point, the same logic that we saw in Chapter 2 applies. So the decision on whether to define an array of pointers versus an array of values comes down to how you use the individual values, not how you use the array or map itself.

當你改變一個切片或者映射的值時,你會看見不同。在這點上,同樣的邏輯,我們在第二章看到已經適用。所以是否定義一個數組指針還是一個數組值主要歸結于如何使用單個值,而不是你如何使用數組或者映射本身。

繼續之前(Before You Continue)

Arrays and maps in Go work much like they do in other languages. If you're used to dynamic arrays, there might be a small adjustment, but append should solve most of your discomfort. If we peek beyond the superficial syntax of arrays, we find slices. Slices are powerful and they have a surprisingly large impact on the clarity of your code.

在Go中數組和映射的工作方式與其他語言非常像。如果你用過動態數組,可能有會有一些需要調整,但是通過append可以解決所有的不適。如果我們拋開數組表面的語法,我們就會發現切片。切片是相當強大的,使用切片對你代碼的整潔性有著非常巨大的影響。

There are edge cases that we haven't covered, but you're not likely to run into them. And, if you do, hopefully the foundation we've built here will let you understand what's going on.

這里有一些邊界例子我們沒有涉及到,但是你不太可能遇見這些例子。另外,如果你遇到了,希望我們已經打下的基礎能讓你理解這是怎么回事。

轉載于:https://my.oschina.net/airhead/blog/2980484

總結

以上是生活随笔為你收集整理的Go Little Book - 第三章 - 字典 ,数组和切片的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。