Golang 知识点总结

617742071 7年前
   <p>本文是由TapirLiu总结的Golang中的一些知识点,对于深入学习Golang很有帮助,所以我特意翻译了一下。</p>    <h3>各种类型复制的时候的花费</h3>    <p>本节标题也可以叫做“各种类型的值的大小” (the sizes of values of all kinds of types),底层可被不同的值共享的数据的大小未被计算。</p>    <p>下面的表格中一个word在32bit操作系统中代表4个字节,在64bit操作系统中代表8个字节,内容基于官方的Go 1.7的编译器。</p>    <table>     <tbody>      <tr>       <th>Type</th>       <th>Cost Of Value Copying (Value Size)</th>      </tr>     </tbody>     <tbody>      <tr>       <td>bool</td>       <td>1 byte</td>      </tr>      <tr>       <td>int8, uint8, byte</td>       <td>1 byte</td>      </tr>      <tr>       <td>int16, uint16</td>       <td>2 bytes</td>      </tr>      <tr>       <td>int32, uint32, rune</td>       <td>4 bytes</td>      </tr>      <tr>       <td>int64, uint64</td>       <td>8 bytes</td>      </tr>      <tr>       <td>int, uint, uintptr</td>       <td>1 word</td>      </tr>      <tr>       <td>string</td>       <td>2 words</td>      </tr>      <tr>       <td>pointer</td>       <td>1 word</td>      </tr>      <tr>       <td>slice</td>       <td>3 words</td>      </tr>      <tr>       <td>map</td>       <td>1 word</td>      </tr>      <tr>       <td>channel</td>       <td>1 word</td>      </tr>      <tr>       <td>function</td>       <td>1 word</td>      </tr>      <tr>       <td>interface</td>       <td>2 words</td>      </tr>      <tr>       <td>struct</td>       <td>the sum of sizes of all fields</td>      </tr>      <tr>       <td>array</td>       <td>(element value size) * (array length)</td>      </tr>     </tbody>    </table>    <h3>可使用内建函数的类型 (len、cap、close、delete、make)</h3>    <table>     <tbody>      <tr>       <th> </th>       <th>len</th>       <th>cap</th>       <th>close</th>       <th>delete</th>       <th>make</th>      </tr>     </tbody>     <tbody>      <tr>       <td>string</td>       <td>Yes</td>       <td> </td>       <td> </td>       <td> </td>       <td> </td>      </tr>      <tr>       <td>array (and array pointer)</td>       <td>Yes</td>       <td>Yes</td>       <td> </td>       <td> </td>       <td> </td>      </tr>      <tr>       <td>slice</td>       <td>Yes</td>       <td>Yes</td>       <td> </td>       <td> </td>       <td>Yes</td>      </tr>      <tr>       <td>map</td>       <td>Yes</td>       <td> </td>       <td> </td>       <td>Yes</td>       <td>Yes</td>      </tr>      <tr>       <td>channel</td>       <td>Yes</td>       <td>Yes</td>       <td>Yes</td>       <td> </td>       <td>Yes</td>      </tr>     </tbody>    </table>    <p>上面的所有类型都可以使用range遍历。</p>    <p>可以用作len函数参数的类型也叫做容器类型。</p>    <h3>内建容器类型的值比较</h3>    <p>假定容器的值可寻址(addressable)。</p>    <table>     <tbody>      <tr>       <th>Type</th>       <th>长度可变</th>       <th>元素可更新</th>       <th>元素可寻址</th>       <th>查找会更改容器的长度</th>       <th>底层元素可以共享</th>      </tr>     </tbody>     <tbody>      <tr>       <td>string</td>       <td>No</td>       <td>No</td>       <td>No</td>       <td>No</td>       <td>Yes</td>      </tr>      <tr>       <td>array</td>       <td>No</td>       <td>Yes</td>       <td>Yes</td>       <td>No</td>       <td>No</td>      </tr>      <tr>       <td>slice</td>       <td>No</td>       <td>Yes</td>       <td>Yes</td>       <td>No</td>       <td>Yes</td>      </tr>      <tr>       <td>map</td>       <td>Yes</td>       <td>Yes</td>       <td>No</td>       <td>No</td>       <td>Yes</td>      </tr>      <tr>       <td>channel</td>       <td>Yes</td>       <td>No</td>       <td>No</td>       <td>Yes</td>       <td>Yes</td>      </tr>     </tbody>    </table>    <h3>组合类型T{...}的值比较</h3>    <table>     <tbody>      <tr>       <th>Type (T)</th>       <th>T{}是类型T的零值?</th>      </tr>     </tbody>     <tbody>      <tr>       <td>struct</td>       <td>Yes</td>      </tr>      <tr>       <td>array</td>       <td>Yes</td>      </tr>      <tr>       <td>slice</td>       <td>No (零值是nil)</td>      </tr>      <tr>       <td>map</td>       <td>No (零值是nil)</td>      </tr>     </tbody>    </table>    <h3>零值是nil的类型</h3>    <table>     <tbody>      <tr>       <th>Type (T)</th>       <th>Size Of T(nil)</th>      </tr>     </tbody>     <tbody>      <tr>       <td>pointer</td>       <td>1 word</td>      </tr>      <tr>       <td>slice</td>       <td>3 words</td>      </tr>      <tr>       <td>map</td>       <td>1 word</td>      </tr>      <tr>       <td>channel</td>       <td>1 word</td>      </tr>      <tr>       <td>function</td>       <td>1 word</td>      </tr>      <tr>       <td>interface</td>       <td>2 words</td>      </tr>     </tbody>    </table>    <p>这些类型的零值的大小和上面类型的大小保持一致。</p>    <h3>编译时被执行的函数</h3>    <p>如果函数在编译时被执行,那么它的返回值是常量。</p>    <table>     <tbody>      <tr>       <th>Function</th>       <th>返回值</th>       <th>编译时便计算?</th>      </tr>     </tbody>     <tbody>      <tr>       <th>unsafe.Sizeof</th>       <td rowspan="3">uintptr</td>       <td rowspan="3">Yes, 总是</td>      </tr>      <tr>       <th>unsafe.Alignof</th>      </tr>      <tr>       <th>unsafe.Offsetof</th>      </tr>      <tr>       <th>len</th>       <td rowspan="2">int</td>       <td rowspan="2">有时候是<br> <a href="/misc/goto?guid=4959735920205594099" rel="nofollow,noindex">Go 规范中讲到</a> :        <ul>         <li>如果s是字符串常量,则len(s)是常量.</li>         <li>如果s是数组或者是数组指针,则len(s)是常量.</li>        </ul> </td>      </tr>      <tr>       <th>cap</th>      </tr>      <tr>       <th>real</th>       <td rowspan="2">float64<br> (默认类型)</td>       <td rowspan="2">有时候是 <p><a href="/misc/goto?guid=4959735920293314289" rel="nofollow,noindex">Go 规范中讲到</a> : 如果s是复数常量,则real(s)和imag(s)是常量.</p> </td>      </tr>      <tr>       <th>imag</th>      </tr>      <tr>       <th>complex</th>       <td>complex128<br> (默认类型)</td>       <td>有时候是 <p><a href="/misc/goto?guid=4959735920293314289" rel="nofollow,noindex">Go 规范中讲到</a> : 如果sr和si都是常量,则complex(sr, si)是常量.</p> </td>      </tr>     </tbody>    </table>    <h3>不能被寻址的值</h3>    <p>下面的值不能被寻址(addresses):</p>    <ul>     <li>bytes in strings:字符串中的字节</li>     <li>map elements:map中的元素</li>     <li>dynamic values of interface values (exposed by type assertions):接口的动态值</li>     <li>constant values:常量</li>     <li>literal values:字面值</li>     <li>package level functions:包级别的函数</li>     <li>methods (used as function values):方法</li>     <li>intermediate values:中间值      <ul>       <li>function callings</li>       <li>explicit value conversions</li>       <li>all sorts of operations, except pointer dereference operations, but including:        <ul>         <li>channel receive operations</li>         <li>sub-string operations</li>         <li>sub-slice operations</li>         <li>addition, subtraction, multiplication, and division, etc.</li>        </ul> </li>      </ul> </li>    </ul>    <p>注意,&T{}相当于tmp := T{}; (&tmp)的语法糖,所以&T{}可合法不意味着T{}可寻址。</p>    <p>下面的值可以寻址:</p>    <ul>     <li>variables</li>     <li>fields of addressable structs</li>     <li>elements of addressable arrays</li>     <li>elements of any slices (whether the slices are addressable or not)</li>     <li>pointer dereference operations</li>    </ul>    <h3>不支持比较的类型</h3>    <p>下面的类型不支持直接比较:</p>    <ul>     <li>map</li>     <li>slice</li>     <li>function</li>     <li>struct types containing incomparable fields</li>     <li>array types with incomparable elements</li>    </ul>    <p>这些不能直接比较的类型不能用做map的key值。</p>    <p>注意:尽管map、slice、function类型不支持直接比较,但是它们的值却可以和nil直接比较。如果两个接口的动态类型不能比较,运行时比较这两个接口会panic,除非其中一个的动态值是untyped nil。</p>    <h3>可命名的源代码元素</h3>    <p>下面的源代码元素可以命名,名称必须是 <a href="/misc/goto?guid=4959735920404129545" rel="nofollow,noindex">Identifier</a></p>    <table>     <tbody>      <tr>       <th> </th>       <th>可以使用_做名称?</th>      </tr>     </tbody>     <tbody>      <tr>       <td>package</td>       <td>No</td>      </tr>      <tr>       <td>import</td>       <td>Yes</td>      </tr>      <tr>       <td>type</td>       <td>Yes</td>      </tr>      <tr>       <td>variable</td>       <td>Yes</td>      </tr>      <tr>       <td>constant</td>       <td>Yes</td>      </tr>      <tr>       <td>function</td>       <td>Yes</td>      </tr>      <tr>       <td>label</td>       <td>Yes</td>      </tr>     </tbody>    </table>    <h3>命名的源代码元素可以使用()分组声明</h3>    <p>下面的类型可以使用()分组生命</p>    <ul>     <li>import</li>     <li>type</li>     <li>variable</li>     <li>constant</li>    </ul>    <p>函数和标签(label)不能使用()分组声明。</p>    <h3>可以在函数内外声明的源代码元素</h3>    <p>下面的类型可以声明在函数内,也可以声明在函数外:</p>    <ul>     <li>type</li>     <li>variable</li>     <li>constant</li>    </ul>    <p>import必须在其它元素的声明的前面(package语句的后面)。</p>    <p>函数在其它函数的外面声明。(译者注:函数变量/匿名函数可以在函数内声明)</p>    <p>标签(label)必须声明在函数内。</p>    <h3>可以返回一个可选bool返回值的表达式</h3>    <p>下面的表达式可以返回一个可选的bool值:</p>    <table>     <tbody>      <tr>       <th> </th>       <th>可选的bool返回值的意义</th>       <th>忽略可选值会影响程序的行为?</th>      </tr>     </tbody>     <tbody>      <tr>       <td><strong>map element access</strong></td>       <td>map中是否包含要</td>       <td>No</td>      </tr>      <tr>       <td><strong>channel value receive</strong></td>       <td>在channel关闭前收到的值是否已发出</td>       <td>No</td>      </tr>      <tr>       <td><strong>type assertion</strong></td>       <td>接口的动态类型是否符合asserted type</td>       <td>Yes</td>      </tr>     </tbody>    </table>    <p>(当可选值被忽略时,如果类型不match则会抛出panic)|</p>    <h3>使用channel机制永远阻塞当前goroutine的方法</h3>    <p>下面的方法都可以永远阻塞当前的goroutine:</p>    <p>1、receive from a channel which no values will be sent to</p>    <pre>  <-make(chan struct{})    // or<-make(<-chan struct{})</pre>    <p>2、send value to a channel which no ones will receive values from</p>    <pre>  make(chan struct{}) <- struct{}{}// ormake(chan<- struct{}) <- struct{}{}</pre>    <p>3、receive value from a nil channel</p>    <pre>  <-chan struct{}(nil)</pre>    <p>4、send value to a nil channel</p>    <pre>  chan struct{}(nil) <- struct{}{}</pre>    <p>5、use a bare select block</p>    <pre>  select{}</pre>    <h3>连接字符串的几种方法</h3>    <p>下面几种方法都可以连接字符串(译者注:不考虑性能):</p>    <p>1、使用+连接字符串。如果连接的字符串少于6个,官方的编译器会对此优化,所以通常使用+简便而有效。</p>    <p>2、使用strings包中的 <a href="/misc/goto?guid=4959636168368606841" rel="nofollow,noindex">strings.Join</a> 连接字符串。</p>    <p>3、使用fmt包中的fmt.Sprintf,fmt.Sprint和fmt.Sprintln连接字符串。这三个方法可以将任意的类型连接成字符串。fmt.Sprintln会在字符串之间加空格,在字符串尾部加新的换行符。如果两个值中的至少一个不是字符串,fmt.Sprint会在它们之间加空格。</p>    <p>4、包bytes的Buffer类型(或者内建函数copy)可以用来构建 byte slice, byte slice可以方便地转换成字符串。</p>    <p> </p>    <p>来自:http://www.udpwork.com/item/16086.html</p>    <p> </p>