开心老狼 發表於 2020-5-28 11:03:00

【GO】Go 三个点省略号"..."使用总结

<p>Go语言中省略号"..."有3种用法,下面会一一介绍。</p>
<p>Tips:以下测试程序中所涉及地址在不同机器打印也不同。<br>目录</p>
<p><strong>使用在数组中</strong></p>
<p><strong>打散Slice</strong></p>
<p><strong>变长的函数参数</strong></p>
<p><span style="color: rgba(255, 0, 0, 1)"><strong>使用在数组中</strong></span></p>
<div class="cnblogs_code">
<pre>q := [...]<span style="color: rgba(0, 0, 255, 1)">int</span>{1,2,3<span style="color: rgba(0, 0, 0, 1)">}
fmt.Printf(</span>"%T\n",q) //"int"</pre>
</div>
<p><br>在数组字面量中,如果省略号"..."出现在数组长度的位置,那么数组的长度由初始化数组的元素个数决定。</p>
<p><span style="color: rgba(255, 0, 0, 1)"><strong>打散Slice</strong></span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">package main

import (
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">fmt</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
)

func main() {
</span><span style="color: rgba(0, 0, 255, 1)">var</span> arr1 []<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">
arr2 :</span>= []<span style="color: rgba(0, 0, 255, 1)">int</span>{<span style="color: rgba(128, 0, 128, 1)">1</span>,<span style="color: rgba(128, 0, 128, 1)">2</span>,<span style="color: rgba(128, 0, 128, 1)">3</span><span style="color: rgba(0, 0, 0, 1)">}
arr1 </span>= append(arr1,<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)   
arr1 </span>= append(arr1,arr2...)    <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">arr2... 将切片arr2打散成 ==&gt; arr1 = append(arr1,1,2,3)</span>
fmt.Printf(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">%v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,arr1)

</span><span style="color: rgba(0, 0, 255, 1)">var</span> arr3 []<span style="color: rgba(0, 0, 255, 1)">byte</span><span style="color: rgba(0, 0, 0, 1)">
arr3 </span>= append(arr3,[]<span style="color: rgba(0, 0, 255, 1)">byte</span>(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">hello</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)...)
fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">%s\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,arr3)
}</span></pre>
</div>
<p>&nbsp;</p>
<p>运行结果:</p>
<p>&nbsp;<img src="https://img2020.cnblogs.com/blog/662503/202005/662503-20200528105609829-903710024.png" alt=""></p>
<p>上面例子中append函数的参数后面的省略号表示如何将一个slice转换为参数列表。</p>
<p><span style="color: rgba(255, 0, 0, 1)"><strong>变长的函数参数</strong></span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">package main

import (
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">fmt</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
)

func f1(parms ...</span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">){
</span><span style="color: rgba(0, 0, 255, 1)">for</span> i,v :=<span style="color: rgba(0, 0, 0, 1)"> range parms {
fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">%v %v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,i,v)
}
}

func main() {
f1(</span><span style="color: rgba(128, 0, 128, 1)">0</span>,<span style="color: rgba(128, 0, 128, 1)">1</span>,<span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">)
}</span></pre>
</div>
<p>运行结果:</p>
<p>&nbsp;<img src="https://img2020.cnblogs.com/blog/662503/202005/662503-20200528110619316-1782260371.png" alt=""></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>在参数列表最后的类型名称之前使用省略号“...”表示声明一个变成函数,调用这个函数的时候可以传递该类型任意数目的参数。</p>
<p><strong><span style="color: rgba(255, 0, 0, 1)">尽管...type参数就像函数体内的slice,但变长函数的类型和带有普通slice参数的函数类型不相同,所以在传参的时候也是有所区别。</span></strong>...type格式的类型只能作为函数的参数类型存在,并且必须是最后一个参数。它是一个语法糖(syntactic sugar),即这种语法对语言的功能并没有影响,但是更方便程序员使用。</p>
<p>如果不使用...type,则必须这样:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">package main

import (
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">fmt</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
)

func f1(parms []</span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">){
</span><span style="color: rgba(0, 0, 255, 1)">for</span> i,v :=<span style="color: rgba(0, 0, 0, 1)"> range parms {
fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">f2:%v %v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,i,v)
}
}

func main() {
b :</span>= []<span style="color: rgba(0, 0, 255, 1)">int</span>{<span style="color: rgba(128, 0, 128, 1)">0</span>,<span style="color: rgba(128, 0, 128, 1)">1</span>,<span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">}
f1(b)
}</span></pre>
</div>
<p><br>结果与上面一样。</p>
<p>以上算是比较基本的用法,但是实际工作中可能会遇到一些别的情况。</p>
<p><strong><span style="color: rgba(255, 0, 0, 1)">情况一</span></strong></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">package main

import (
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">fmt</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
)

func f1(parms ...</span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">){
fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">%T\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,parms)
</span><span style="color: rgba(0, 0, 255, 1)">for</span> i,v :=<span style="color: rgba(0, 0, 0, 1)"> range parms {
fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">f1:%v %v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,i,v)
}
}

func main() {
b :</span>= []<span style="color: rgba(0, 0, 255, 1)">int</span>{<span style="color: rgba(128, 0, 128, 1)">0</span>,<span style="color: rgba(128, 0, 128, 1)">1</span>,<span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">f1(b) </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">error</span>
<span style="color: rgba(0, 0, 0, 1)">f1(b...)
}<br></span></pre>
</div>
<p><img src="https://img2020.cnblogs.com/blog/662503/202005/662503-20200528110725437-642868224.png" alt=""></p>
<p>上面已经说明:<strong><span style="color: rgba(255, 0, 0, 1)">尽管...type参数就像函数体内的slice,但变长函数的类型和带有普通slice参数的函数类型不相同。</span></strong>所以f1(b)会发生错误,因为类型不匹配。而这里在slice后面加...,将slice打散,传入f1。</p>
<p>同时也可以知道,parms类型是[]int,所以在函数f1里面,parms就是一个int类型的切片。</p>
<p><strong><span style="color: rgba(255, 0, 0, 1)">情况二</span></strong></p>
<div class="cnblogs_Highlighter">
<pre class="brush:go;gutter:true;">package main

import (
"fmt"
)

func f2(a ...int){
fmt.Printf("f2 %T\n",a)
fmt.Printf("f2 %v\n",a)
fmt.Printf("f2 %p\n",a)
}

func f1(a ...int){
fmt.Printf("f1 %v\n",a)
fmt.Printf("f1 %p\n",a)
//f2(a) //error
f2(a...)
}

func main() {
f1(1,2,3)
}</pre>
</div>
<p><img src="https://img2020.cnblogs.com/blog/662503/202005/662503-20200528110839556-1322014240.png" alt=""></p>
<p>从情况一知道,在f1中a是slice,再次传入到f2函数中,必须将slice打散操作,不然发生类型不匹配的错误。</p>
<p>但是我们把 ...int 改为 ...interface{} ,再看下面的例子:</p>
<p>&nbsp;</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">package main

import (
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">fmt</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
)

func f2(a ...</span><span style="color: rgba(0, 0, 255, 1)">interface</span><span style="color: rgba(0, 0, 0, 1)">{}){
fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">f2 %T\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,a)
fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">f2 %v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,a)
fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">f2 %p\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,a)
}

func f1(a ...</span><span style="color: rgba(0, 0, 255, 1)">interface</span><span style="color: rgba(0, 0, 0, 1)">{}){
fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">f1 %v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,a)
fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">f1 %p\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,a)
f2(a)
f2(a...)
}

func main() {
f1(</span><span style="color: rgba(128, 0, 128, 1)">1</span>,<span style="color: rgba(128, 0, 128, 1)">2</span>,<span style="color: rgba(128, 0, 128, 1)">3</span><span style="color: rgba(0, 0, 0, 1)">)
}</span></pre>
</div>
<p><img src="https://img2020.cnblogs.com/blog/662503/202005/662503-20200528110917735-1030290067.png" alt=""></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><br>发现在f2(a)没有发生错误,但是仔细看看打印的结果[]是数组为元素的数组类型。这都归功于interface{}这个万能类型,它将f2(a)中的a作为一个参数传入,a在f2函数中,是[]interface{}类型。比如:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">package main

import (
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">fmt</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
)

func f1(a ...</span><span style="color: rgba(0, 0, 255, 1)">interface</span><span style="color: rgba(0, 0, 0, 1)">{}){
fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">f1 %v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,a)
}

func main() {
arr :</span>= []<span style="color: rgba(0, 0, 255, 1)">int</span>{<span style="color: rgba(128, 0, 128, 1)">1</span>,<span style="color: rgba(128, 0, 128, 1)">2</span>,<span style="color: rgba(128, 0, 128, 1)">3</span><span style="color: rgba(0, 0, 0, 1)">}
arr2 :</span>= []<span style="color: rgba(0, 0, 255, 1)">int</span>{<span style="color: rgba(128, 0, 128, 1)">11</span>,<span style="color: rgba(128, 0, 128, 1)">22</span>,<span style="color: rgba(128, 0, 128, 1)">33</span><span style="color: rgba(0, 0, 0, 1)">}
f1(arr,arr2,</span><span style="color: rgba(128, 0, 128, 1)">111</span>,<span style="color: rgba(128, 0, 128, 1)">222</span>,<span style="color: rgba(128, 0, 128, 1)">333</span><span style="color: rgba(0, 0, 0, 1)">
}</span></pre>
</div>
<p><strong><span style="color: rgba(255, 0, 0, 1)"><img src="https://img2020.cnblogs.com/blog/662503/202005/662503-20200528110934100-2066832385.png" alt=""></span></strong></p>
<p>&nbsp;</p>
<p><strong><span style="color: rgba(255, 0, 0, 1)">情况三</span></strong></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">package main

import (
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">fmt</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
)

func f1(a ...</span><span style="color: rgba(0, 0, 255, 1)">interface</span><span style="color: rgba(0, 0, 0, 1)">{}){
fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">f1 %v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,a)
}

func main() {
arr :</span>= []<span style="color: rgba(0, 0, 255, 1)">int</span>{<span style="color: rgba(128, 0, 128, 1)">1</span>,<span style="color: rgba(128, 0, 128, 1)">2</span>,<span style="color: rgba(128, 0, 128, 1)">3</span><span style="color: rgba(0, 0, 0, 1)">}
f1(arr...)
}</span></pre>
</div>
<p>&nbsp;<img src="https://img2020.cnblogs.com/blog/662503/202005/662503-20200528111000687-1559642506.png" alt="">&nbsp;</p>
<p>这和情况一看起来差不多,但是这里怎么出错了?</p>
<p>我们从错误提示可以看出:[]int 不能作为 []interface{}类型传入f1。换句话说,就是类型不匹配。</p>
<p>但是interface{}不是万能类型嘛?从情况二可以看出。</p>
<p>这里可能是一个误区,虽然interface{}是万能类型,但是[]interface{}并不是万能类型,它本质是slice,只不过slice的成员都是万能类型interface{},就像[]int和[]string是不同类型slice,所以错误是因为类型不匹配。也可以看看官方怎么解释[]interface{}。</p>
<p>结合下面例子再理解。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">package main

import (
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">fmt</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
)

func f2(a </span><span style="color: rgba(0, 0, 255, 1)">interface</span><span style="color: rgba(0, 0, 0, 1)">{}){
fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">f2 %v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,a)
}

func f3(a []</span><span style="color: rgba(0, 0, 255, 1)">interface</span><span style="color: rgba(0, 0, 0, 1)">{}){
fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">f3 %v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,a)
}

func f4(a []</span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">){
fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">f4 %v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,a)
}

func main() {
arr :</span>= []<span style="color: rgba(0, 0, 255, 1)">int</span>{<span style="color: rgba(128, 0, 128, 1)">1</span>,<span style="color: rgba(128, 0, 128, 1)">2</span>,<span style="color: rgba(128, 0, 128, 1)">3</span><span style="color: rgba(0, 0, 0, 1)">}

f2(arr) </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">[]int -&gt; interface{}   

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">f3(arr)    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">error 类型不匹配[]int -&gt; []interface{}</span>
<span style="color: rgba(0, 0, 0, 1)">
f4(arr)
}</span></pre>
</div>
<p><img src="https://img2020.cnblogs.com/blog/662503/202005/662503-20200528111051191-664275103.png" alt=""></p>
<p>那如何修改情况三第一个例子,如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">package main

import (
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">fmt</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
)

func f1(a ...</span><span style="color: rgba(0, 0, 255, 1)">interface</span><span style="color: rgba(0, 0, 0, 1)">{}){
fmt.Printf(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">f1 %v\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,a)
}

func main() {
</span><span style="color: rgba(0, 0, 255, 1)">var</span> arr []<span style="color: rgba(0, 0, 255, 1)">interface</span><span style="color: rgba(0, 0, 0, 1)">{}
arr </span>= append(arr,<span style="color: rgba(128, 0, 128, 1)">1</span>,<span style="color: rgba(128, 0, 128, 1)">2</span>,<span style="color: rgba(128, 0, 128, 1)">3</span><span style="color: rgba(0, 0, 0, 1)">)
f1(arr...)
}</span></pre>
</div>
<p><img src="https://img2020.cnblogs.com/blog/662503/202005/662503-20200528111110040-660553294.png" alt=""></p>
<p>以上大概就是Go语言的省略号"..."的所有用法和遇到的问题了。</p>
<p><strong><span style="color: rgba(255, 0, 0, 1)">参考文章:</span></strong></p>
<p>http://c.biancheng.net/view/60.html<br>https://blog.csdn.net/jeffrey11223/article/details/79166724</p><br><br>
来源:https://www.cnblogs.com/opensmarty/p/12979169.html
頁: [1]
查看完整版本: 【GO】Go 三个点省略号"..."使用总结