Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 1 | # Introduction |
| 2 | |
| 3 | Given that you can assign a variable of any type to an ` interface{} `, often people will try code like the following. |
| 4 | ``` |
Dave Day | 0d6986a | 2014-12-10 15:02:18 +1100 | [diff] [blame] | 5 | var dataSlice []int = foo() |
| 6 | var interfaceSlice []interface{} = dataSlice |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 7 | ``` |
| 8 | This gets the error |
| 9 | ``` |
| 10 | cannot use dataSlice (type []int) as type []interface { } in assignment |
| 11 | ``` |
| 12 | |
| 13 | The question then, "Why can't I assign any slice to an ` []interface{} `, when I can assign any type to an ` interface{} `?" |
| 14 | |
| 15 | ## Why? |
| 16 | |
| 17 | There are two main reasons for this. |
| 18 | |
| 19 | The first is that a variable with type ` []interface{} ` is not an interface! It is a slice whose element type happens to be ` interface{} `. But even given this, one might say that the meaning is clear. |
| 20 | |
| 21 | Well, is it? A variable with type ` []interface{} ` has a specific memory layout, known at compile time. |
| 22 | |
| 23 | Each ` interface{} ` takes up two words (one word for the type of what is contained, the other word for either the contained data or a pointer to it). As a consequence, a slice with length N and with type ` []interface{} ` is backed by a chunk of data that is N\*2 words long. |
| 24 | |
| 25 | This is different than the chunk of data backing a slice with type ` []MyType ` and the same length. Its chunk of data will be N\*sizeof(MyType) words long. |
| 26 | |
| 27 | The result is that you cannot quickly assign something of type ` []MyType ` to something of type ` []interface{} `; the data behind them just look different. |
| 28 | |
| 29 | ## What can I do instead? |
| 30 | |
| 31 | It depends on what you wanted to do in the first place. |
| 32 | |
| 33 | If you want a container for an arbitrary array type, and you plan on changing back to the original type before doing any indexing operations, you can just use an ` interface{} `. The code will be generic (if not compile-time type-safe) and fast. |
| 34 | |
| 35 | If you really want a ` []interface{} ` because you'll be doing indexing before converting back, or you are using a particular interface type and you want to use its methods, you will have to make a copy of the slice. |
| 36 | ``` |
Dave Day | 0d6986a | 2014-12-10 15:02:18 +1100 | [diff] [blame] | 37 | var dataSlice []int = foo() |
| 38 | var interfaceSlice []interface{} = make([]interface{}, len(dataSlice)) |
| 39 | for i, d := range dataSlice { |
| 40 | interfaceSlice[i] = d |
| 41 | } |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 42 | ``` |