golang不能直接将其他类型slice赋值给interface类型的slice

其实这个问题在前面可变函数参数列表中提到了,就是不能因为interface{}是万用类型的就将其他类型的变量切片赋值给它,原文链接

问题如下:

I’m writing some code, and I need it to catch the arguments and pass them through fmt.Println
(I want its default behaviour, to write arguments separated by spaces and followed by a newline). However it takes []interface {} but flag.Args() returns a []string.
Here’s the code example:

<span class="kwd">package</span><span class="pln"> main

</span><span class="kwd">import</span> <span class="pun">(</span>
    <span class="str">"fmt"</span>
    <span class="str">"flag"</span>
<span class="pun">)</span><span class="pln">

func main</span><span class="pun">()</span> <span class="pun">{</span><span class="pln">
    flag</span><span class="pun">.</span><span class="typ">Parse</span><span class="pun">()</span><span class="pln">
    fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">flag</span><span class="pun">.</span><span class="typ">Args</span><span class="pun">()...)</span>
<span class="pun">}</span>`</pre>
This returns the following error:
<pre class="lang-golang prettyprint prettyprinted">`<span class="pun">./</span><span class="pln">example</span><span class="pun">.</span><span class="pln">go</span><span class="pun">:</span><span class="lit">10</span><span class="pun">:</span><span class="pln"> cannot </span><span class="kwd">use</span><span class="pln"> args </span><span class="pun">(</span><span class="pln">type </span><span class="pun">[]</span><span class="kwd">string</span><span class="pun">)</span> <span class="kwd">as</span><span class="pln"> type </span><span class="pun">[]</span><span class="kwd">interface</span> <span class="pun">{}</span> <span class="kwd">in</span> <span class="kwd">function</span><span class="pln"> argument</span>`</pre>
Is this a bug? Shouldn't `fmt.Println` take **any** array? By the way, I've also tried to do this:
<pre class="lang-golang prettyprint prettyprinted">`<span class="kwd">var</span><span class="pln"> args </span><span class="pun">=</span> <span class="pun">[]</span><span class="kwd">interface</span><span class="pun">{}(</span><span class="pln">flag</span><span class="pun">.</span><span class="typ">Args</span><span class="pun">())</span>`</pre>
but I get the following error:
<pre class="lang-golang prettyprint prettyprinted">`<span class="pln">cannot convert flag</span><span class="pun">.</span><span class="typ">Args</span><span class="pun">()</span> <span class="pun">(</span><span class="pln">type </span><span class="pun">[]</span><span class="kwd">string</span><span class="pun">)</span><span class="pln"> to type </span><span class="pun">[]</span><span class="kwd">interface</span> <span class="pun">{}</span>`</pre>
Is there a "Go" way to workaround this?

----------------答案如下----------------

</div>
<div class="post-text">

This is not a bug. `fmt.Println()` requires a `[]interface{}` type. That means, it must be a slice of `interface{}` values and not "any slice". In order to convert the slice, you will need to loop over and copy each element.
<pre class="lang-golang prettyprint prettyprinted">`<span class="pln">old </span><span class="pun">:=</span><span class="pln"> flag</span><span class="pun">.</span><span class="typ">Args</span><span class="pun">()</span>
<span class="kwd">new</span> <span class="pun">:=</span><span class="pln"> make</span><span class="pun">([]</span><span class="kwd">interface</span><span class="pun">{},</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">old</span><span class="pun">))</span>
<span class="kwd">for</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> v </span><span class="pun">:=</span><span class="pln"> range old </span><span class="pun">{</span>
    <span class="kwd">new</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span> <span class="pun">=</span><span class="pln"> v
</span><span class="pun">}</span><span class="pln">
fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="kwd">new</span><span class="pun">...)</span>

The reason you can’t use any slice is that conversion between a []string and a []interface{} requires the memory layout to be changed and happens in O(n) time. Converting a type to an interface{} requires O(1) time. If they made this for loop unnecessary, the compiler would still need to insert it.


———-相关评论———-












































If each iteration requires O(1) time, wouldn’t the whole loop need O(n) time?cruizh Oct 20 ‘12 at 17:06










If every element in the slice satisfies interface{}, then a function receiving []string instead should have no problem, since every element inside satisfies the interface, is it?cruizh Oct 20 ‘12 at 17:14








2










2


Yes, each iteration requires O(1) time and the loop requires O(n) time. That is what I said. As for the function receiving a []string, it expects a interface{}. An interface{} has a different memory layout from a string so the fact that each element needs to be converted is the problem.Stephen Weinberg Oct 20 ‘12 at 17:52








1


@karlrh: No, suppose the Println function modifies the slice, and sets some elements (it doesn’t, but suppose it does). Then it can put any interface{} into the slice, which should only have strings. What you really want is something like the Java Generics wildcard Slice&lt;? extends []interface{}&gt;, but that doesn’t exist in Go.newacct Oct 21 ‘12 at 2:05










but why append can accept any slice?zhaozhi Jan 23 ‘14 at 8:52








4


Append is magical. It is built-in and treated specially by the language. Other examples include new(), len(), and copy(). golang.org/ref/spec#Appending_and_copying_slicesStephen Weinberg Jan 23 ‘14 at 17:52








2












Explicit conversion to interface{} is unnecessary, instead of new[i] = interface{}(v) you can simply write new[i] = v.icza Jun 2 ‘15 at 6:57










Today I learned ‘new’ is a not a reserve keyword! Nor is make!Sridhar Aug 13 ‘15 at 12:00

转载请注明来源链接 http://just4fun.im/2017/01/07/golang-e4-b8-8d-e8-83-bd-e7-9b-b4-e6-8e-a5-e5-b0-86-e5-85-b6-e4-bb-96-e7-b1-bb-e5-9e-8bslice-e8-b5-8b-e5-80-bc-e7-bb-99interface-e7-b1-bb-e5-9e-8b-e7-9a-84slice/ 尊重知识,谢谢:)