深入Go语言 - 1

BroderickDa 8年前
   <p>准备写一个Go 语言深入开发的系列,分为三个部分。第一部分为Go 语言的深入剖析,第二部分为一些官方库的深入开发,第三部分为一些第三方库的介绍。</p>    <h2>奇怪的变量名</h2>    <p>标志符用来命名变量、类型、函数名等,最常规的,我们使用普通的拉丁字母和数字作为标志符,或者以下划线开始。</p>    <pre>  <code class="language-go">str := "hello world"  fmt.Println(str)    _str09 := "hello w0rld"  fmt.Println(_str09)  </code></pre>    <p>但是根据Go语言规范,任何Unicode编码的字符和下划线都可以作为标识符的第一个字母,之后可以是任意的Unicode的字符或者数字。允许的unicode字符为Unicode分类中的Lu、Ll、Lt、Lm、Lo等字符,比如中文、希腊字母等。你可以在参考链接中查看相应的Unicode字符分类。</p>    <pre>  <code class="language-go">一个变量 := "hello 世界"  fmt.Println(一个变量)    ÆõĦǗΩצˮ? := "hello ¾"  fmt.Println(ÆõĦǗΩצˮ?)  </code></pre>    <p>标识符业可以是类型名、函数名等:</p>    <pre>  <code class="language-go">type学生struct{   姓名 string  }    type小学生 学生    type조선말interface{  }    func函数名() {   fmt.Println("I am a function")  }  </code></pre>    <p>当然,我相信绝大部分的程序员都会以普通的拉丁字母和数字作为标识符的,这样阅读起来更符合大众的习惯。在搞怪的情况下,可以尝试一下这些"奇怪"字符。</p>    <ul>     <li><a href="/misc/goto?guid=4959674357932723259" rel="nofollow,noindex">https://en.wikipedia.org/wiki/List_of_Unicode_characters</a></li>     <li><a href="/misc/goto?guid=4959674358014572638" rel="nofollow,noindex">http://www.unicode.org/Public/UNIDATA/UnicodeData.txt</a></li>     <li><a href="/misc/goto?guid=4959674358096533057" rel="nofollow,noindex">http://www.fileformat.info/info/unicode/category/index.htm</a></li>    </ul>    <h2>预定义标识符</h2>    <p>首先看下面一段代码,看看是否能变易成功:</p>    <pre>  <code class="language-go">funcmain() {  varinil=100   fmt.Println(i)    varisSuccessbool=100   fmt.Println(isSuccess)    }  </code></pre>    <p>你肯定会说,不可能成功,类型不对呀。</p>    <p>没错,不可能将一个整数赋值给布尔类型的变量的。 那么你能不能加在方法外面加几行,让代码编译成功?</p>    <p>请注意,以下标识符实预先定义的标识符,而不是关键字,这意味着我们可以"覆盖"这些标识符的定义。</p>    <pre>  <code class="language-go">Types:  boolbytecomplex64complex128errorfloat32float64  intint8int16int32int64runestring  uintuint8uint16uint32uint64uintptr    Constants:  truefalseiota    Zero value:  nil    Functions:  appendcapclosecomplexcopydeleteimaglen  makenewpanicprintprintlnrealrecover  </code></pre>    <p>比如加上下面几行代码,程序就可以编译通过。</p>    <pre>  <code class="language-go">packagemain    import"fmt"    typenilint  typebooluint8    funcmain() {  varinil=100   fmt.Println(i)    varisSuccessbool=100   fmt.Println(isSuccess)    }  </code></pre>    <h2>整数字面值</h2>    <p>Go语言不像其它语言, 如C++、Java,在声明数值类型的时候可以通过后缀如ll等表明变量的类型, 目前Go语言不提供这个功能。</p>    <p>如果值以0开始,则代表8进制。</p>    <p>如果值以0x或者0X开始,则代表16进制。</p>    <p>浮点数和其它语言的表示法相同。</p>    <p>复数表示法业和其它语言一致。</p>    <h2>Rune</h2>    <p>其它语言如Java、C#,字符串的字符操作很直观,但是Go语言的字符串的实现比较特殊,这可能和Go设计者的几位大牛有关,它保留着Unix和C的痕迹。</p>    <p>Java语言规范规定,Java的char类型是UTF-16的code unit,也就是两个字节,字符串是UTF-16 code unit的序列,因此每个字符都是定长的,要想获得某个位置字符,很容易计算出它的字节在字符串中的位置。</p>    <p>Go语言使用UTF-8作为字符串的内部编码,所以在没有byte字面量的情况下,字符串都是使用UTF-8编码的。因此对于大部分字符串都是ascii字符的情况下,占用的内存空间就会大大减少,但是带来的问题是,从字符串的字节slice中查找第n个字符比较麻烦,因为不能直接的计算出来。</p>    <p>这里通称所有字母都为字符,其实是不准确的,在Unicodde规范中,它们称之为 code point , 比如code point U+2318代表 ⌘ 。<br> A 既是一个字符,也是一个code point: U+00E0。</p>    <p>code point有点拗口,所以Go语言用 rune 来表示,你只需记住它们是等价的即可。</p>    <p>rune有单引号定义,它包含单一的一个 code point。</p>    <pre>  <code class="language-go">varrrune='文'  fmt.Printf("%#U\n", r)  </code></pre>    <p>通过 range 可以遍历一个字符串中所有的rune:</p>    <pre>  <code class="language-go">constnihongo ="one world世界大同"  forindex, runeValue :=rangenihongo {   fmt.Printf("%#U starts at byte position %d\n", runeValue, index)  }  </code></pre>    <p>因为字符串是以UTF-8编码的,通过输出可以看到ascii字母只用一个字节,而这几个中文汉字每个汉字用了3个字节。</p>    <p>要想获得字符串中包含几个字符(rune),下面的方法是不对的,它返回的是字符处内部的字slice的长度((9 + 4*3 =21):</p>    <pre>  <code class="language-go">conststr ="one world世界大同"  fmt.Println(len(str))  </code></pre>    <p>我记得有个Go语言写的框架,在获取一篇文章的前N个字符的时候,就直接用 len 方法计算,这对于中文文章来说,肯定不对,截取的字符要少于期望的字符数,而且可能截取半个字符。</p>    <p>要想在字符串中操作rune,可以使用 package <a href="/misc/goto?guid=4959674358176373300" rel="nofollow,noindex">unicode/utf8</a> ,它提供了一组处理字符串和rune的方法,<br> 比如我们正确计算一个字符串中包含的rune的数量:</p>    <pre>  <code class="language-go">fmt.Println(utf8.RuneCountInString(str))  </code></pre>    <p>字符串以两端用双引号包含的方式定义,允许使用转义字符存在或者"\"+byte方式包含rune。</p>    <pre>  <code class="language-go">"Hello, world!\n"  "世界"  "\u65e5本\U00008a9e"  "\xff\u00FF"  "\uD800"//非法  "\U00110000"//非法  </code></pre>    <ul>     <li><a href="/misc/goto?guid=4959674358255465251" rel="nofollow,noindex">https://blog.golang.org/strings</a></li>     <li><a href="/misc/goto?guid=4959674358332997174" rel="nofollow,noindex">https://blog.golang.org/constants</a></li>    </ul>    <h2>Rune和字符串互转</h2>    <p>直接通过 T(x) 类型转换即可。</p>    <pre>  <code class="language-go">r := []rune(str)  fmt.Printf("%#v\n", r)  str = string(r)  fmt.Printf("%#v\n", str)  </code></pre>    <p>另外 package <a href="/misc/goto?guid=4959674358412469326" rel="nofollow,noindex">strconv</a> 也提供了格式化rune为字符串的一些方法, 比如</p>    <pre>  <code class="language-go">s := strconv.QuoteRune('☺')  fmt.Println(s)  </code></pre>    <p> </p>    <p>来自: <a href="/misc/goto?guid=4959674358493549738" rel="nofollow">http://colobu.com/2016/06/15/dive-into-go-1/</a></p>    <p> </p>