﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-少年阿宾-随笔分类-golang</title><link>http://www.blogjava.net/stevenjohn/category/55274.html</link><description>那些青春的岁月</description><language>zh-cn</language><lastBuildDate>Thu, 03 Aug 2017 05:37:30 GMT</lastBuildDate><pubDate>Thu, 03 Aug 2017 05:37:30 GMT</pubDate><ttl>60</ttl><item><title>GoLang之方法与接口</title><link>http://www.blogjava.net/stevenjohn/archive/2017/08/03/432720.html</link><dc:creator>abin</dc:creator><author>abin</author><pubDate>Thu, 03 Aug 2017 03:34:00 GMT</pubDate><guid>http://www.blogjava.net/stevenjohn/archive/2017/08/03/432720.html</guid><wfw:comment>http://www.blogjava.net/stevenjohn/comments/432720.html</wfw:comment><comments>http://www.blogjava.net/stevenjohn/archive/2017/08/03/432720.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/stevenjohn/comments/commentRss/432720.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/stevenjohn/services/trackbacks/432720.html</trackback:ping><description><![CDATA[<p>Go语言没有沿袭传统面向对象编程中的诸多概念，比如继承、虚函数、构造函数和析构函数、隐藏的this指针等。</p> <p>&nbsp;</p> <h2>方法</h2> <p><span style="line-height: 1.5;">Go 语言中同时有函数和方法。<span style="color: #ff0000;">方法就是一个包含了接受者（receiver）的函数</span>，receiver可以是内置类型或者结构体类型的一个值或者是一个指针。所有给定类型的方法属于该类型的方法集。<br /></span></p> <p>如下面的这个例子，定义了一个新类型Integer，它和int一样，只是为它内置的int类型增加了个新方法Less()</p> <div><div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div> <pre>type Integer <span style="color: #0000ff;">int</span>   func (a Integer) Less(b Integer) bool {     return a &lt; b  }  func main() {     var a Integer = 1       <span style="color: #0000ff;">if</span> a.Less(2) {         fmt.Println("less then 2")     }    }</pre> <div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div></div> <p>可以看出，Go语言在自定义类型的对象中没有C++/Java那种隐藏的this指针，而是在定义成员方法时显式声明了其所属的对象。</p> <p>&nbsp;</p> <p>method的语法如下：</p> <div> <pre>func (r ReceiverType) funcName(parameters) (results)</pre> </div> <p>当调用method时，会将receiver作为函数的第一个参数：</p> <div> <pre>funcName(r, parameters);</pre> </div> <p>所以，receiver是值类型还是指针类型要看method的作用。如果要修改对象的值，就需要传递对象的指针。</p> <p>指针作为Receiver会对实例对象的内容发生操作,而普通类型作为Receiver仅仅是以副本作为操作对象,并不对原实例对象发生操作。</p> <div><div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div> <pre>func (a *Ingeger) Add(b Integer) {     *a += b }  func main() {     var a Integer = 1      a.Add(3)     fmt.Println("a =", a)     //  a = 4 }</pre> <div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div></div> <p>如果Add方法不使用指针，则a返回的结果不变，这是因为Go语言函数的参数也是基于值传递。</p> <p>注意：<span style="color: #ff0000;">当方法的接受者是指针时，即使用值类型调用那么方法内部也是对指针的操作。</span></p> <p>&nbsp;</p> <p>之前说过，Go语言没有构造函数的概念，通常使用一个全局函数来完成。例如：</p> <div><div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div> <pre>func NewRect(x, y, width, height float64) *Rect {     return &amp;Rect{x, y, width, height} }     func main() {     rect1 := NewRect(1,2,10,20)     fmt.Println(rect1.width) }</pre> <div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div></div> <p>&nbsp;</p> <p>&nbsp;</p> <hr /> <h3><span style="font-size: 14px; line-height: 1.5;">匿名组合</span></h3> <p><span style="line-height: 1.5;">Go语言提供了继承，但是采用了组合的语法，我们将其称为匿名组合，例如：</span></p> <div><div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div> <pre>type Base struct {     name string }  func (base *Base) Set(myname string) {     base.name = myname }  func (base *Base) Get() string {     return base.name }  type Derived struct {     Base     age <span style="color: #0000ff;">int</span>  }  func (derived *Derived) Get() (nm string, ag <span style="color: #0000ff;">int</span>) {     return derived.name, derived.age }   func main() {     b := &amp;Derived{}      b.Set("sina")     fmt.Println(b.Get()) }</pre> <div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div></div> <p>例子中，在Base类型定义了get()和set()两个方法，而Derived类型继承了Base类，并改写了Get()方法，在Derived对象调用Set()方法，会加载基类对应的方法；而调用Get()方法时，加载派生类改写的方法。</p> <p>&nbsp;</p> <p>组合的类型和被组合的类型包含同名成员时，&nbsp;会不会有问题呢？可以参考下面的例子：</p> <div><div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div> <pre>type Base struct {     name string     age <span style="color: #0000ff;">int</span> }  func (base *Base) Set(myname string, myage <span style="color: #0000ff;">int</span>) {     base.name = myname     base.age = myage }  type Derived struct {     Base     name string }  func main() {     b := &amp;Derived{}      b.Set("sina", 30)     fmt.Println("b.name =",b.name, "\tb.Base.name =", b.Base.name)     fmt.Println("b.age =",b.age, "\tb.Base.age =", b.Base.age) }</pre> <div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div></div> <p>&nbsp;</p> <p>&nbsp;</p> <p>&nbsp;</p> <hr /> <h2>值语义和引用语义</h2> <p>值语义和引用语义的差别在于赋值，比如</p> <div> <pre>b = a b.Modify()</pre> </div> <p><span style="line-height: 1.5;">如果b的修改不会影响a的值，那么此类型属于值类型；如果会影响a的值，那么此类型是引用类型。</span></p> <p>Go语言中的大多数类型都基于值语义，包括：</p> <ul> <li>基本类型，如byte、int、bool、float32、string等；</li> <li><span style="line-height: 1.5;">复合类型，如arry、struct、pointer等；</span></li> </ul> <p>&nbsp;</p> <p>C语言中的数组比较特别，通过函数传递一个数组的时候基于引用语义，但是在结构体定义数组变量的时候基于值语义。而在Go语言中，数组和基本类型没有区别，是很纯粹的值类型，例如：</p> <div> <pre>var a = [3] <span style="color: #0000ff;">int</span>{1,2,3} var b = a b[1]++ fmt.Println(a, b)   // [1 2 3] [1 3 3]</pre> </div> <p>从结果看，b=a赋值语句是数组内容的完整复制，要想表达引用，需要用指针：</p> <div> <pre>var a = [3] <span style="color: #0000ff;">int</span>{1,2,3} var b = &amp;a　　　　// 引用语义 b[1]++ fmt.Println(a, b)   // [1 3 3] [1 3 3]</pre> </div> <p>&nbsp;</p> <p>&nbsp;</p> <hr /> <h2>接口</h2> <p>Interface 是一组抽象方法（未具体实现的方法/仅包含方法名参数返回值的方法）的集合，如果实现了 interface 中的所有方法，即该类/对象就实现了该接口。</p> <p>Interface 的声明格式：</p> <div> <pre>type interfaceName interface {       //方法列表   }  </pre> </div> <p>Interface 可以被任意对象实现，一个类型/对象也可以实现多个 interface；<br /><span style="background-color: #ffff00;">interface的变量可以持有任意实现该interface类型的对象。</span></p> <p>&nbsp;如下面的例子：</p> <div><div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div> <pre>package main      import <span style="color: #800000;">"</span><span style="color: #800000;">fmt</span><span style="color: #800000;">"</span>      type Human <span style="color: #0000ff;">struct</span> {         name <span style="color: #0000ff;">string</span>         age <span style="color: #0000ff;">int</span>         phone <span style="color: #0000ff;">string</span>     }      type Student <span style="color: #0000ff;">struct</span> {         Human <span style="color: #008000;">//</span><span style="color: #008000;">匿名字段</span>         school <span style="color: #0000ff;">string</span>         loan float32     }      type Employee <span style="color: #0000ff;">struct</span> {         Human <span style="color: #008000;">//</span><span style="color: #008000;">匿名字段</span>         company <span style="color: #0000ff;">string</span>         money float32     }      <span style="color: #008000;">//</span><span style="color: #008000;">Human实现SayHi方法</span>     func (h Human) SayHi() {         fmt.Printf(<span style="color: #800000;">"</span><span style="color: #800000;">Hi, I am %s you can call me on %s\n</span><span style="color: #800000;">"</span>, h.name, h.phone)     }      <span style="color: #008000;">//</span><span style="color: #008000;">Human实现Sing方法</span>     func (h Human) Sing(lyrics <span style="color: #0000ff;">string</span>) {         fmt.Println(<span style="color: #800000;">"</span><span style="color: #800000;">La la la la...</span><span style="color: #800000;">"</span>, lyrics)     }      <span style="color: #008000;">//</span><span style="color: #008000;">Employee重载Human的SayHi方法</span>     func (e Employee) SayHi() {         fmt.Printf(<span style="color: #800000;">"</span><span style="color: #800000;">Hi, I am %s, I work at %s. Call me on %s\n</span><span style="color: #800000;">"</span>, e.name,             e.company, e.phone)         }      <span style="color: #008000;">//</span><span style="color: #008000;"> Interface Men被Human,Student和Employee实现     </span><span style="color: #008000;">//</span><span style="color: #008000;"> 因为这三个类型都实现了这两个方法</span>     type Men <span style="color: #0000ff;">interface</span> {         SayHi()         Sing(lyrics <span style="color: #0000ff;">string</span>)     }      func main() {         mike := Student{Human{<span style="color: #800000;">"</span><span style="color: #800000;">Mike</span><span style="color: #800000;">"</span>, <span style="color: #800080;">25</span>, <span style="color: #800000;">"</span><span style="color: #800000;">222-222-XXX</span><span style="color: #800000;">"</span>}, <span style="color: #800000;">"</span><span style="color: #800000;">MIT</span><span style="color: #800000;">"</span>, <span style="color: #800080;">0.00</span>}         paul := Student{Human{<span style="color: #800000;">"</span><span style="color: #800000;">Paul</span><span style="color: #800000;">"</span>, <span style="color: #800080;">26</span>, <span style="color: #800000;">"</span><span style="color: #800000;">111-222-XXX</span><span style="color: #800000;">"</span>}, <span style="color: #800000;">"</span><span style="color: #800000;">Harvard</span><span style="color: #800000;">"</span>, <span style="color: #800080;">100</span>}         sam := Employee{Human{<span style="color: #800000;">"</span><span style="color: #800000;">Sam</span><span style="color: #800000;">"</span>, <span style="color: #800080;">36</span>, <span style="color: #800000;">"</span><span style="color: #800000;">444-222-XXX</span><span style="color: #800000;">"</span>}, <span style="color: #800000;">"</span><span style="color: #800000;">Golang Inc.</span><span style="color: #800000;">"</span>, <span style="color: #800080;">1000</span>}         tom := Employee{Human{<span style="color: #800000;">"</span><span style="color: #800000;">Tom</span><span style="color: #800000;">"</span>, <span style="color: #800080;">37</span>, <span style="color: #800000;">"</span><span style="color: #800000;">222-444-XXX</span><span style="color: #800000;">"</span>}, <span style="color: #800000;">"</span><span style="color: #800000;">Things Ltd.</span><span style="color: #800000;">"</span>, <span style="color: #800080;">5000</span>}          <span style="color: #008000;">//</span><span style="color: #008000;">定义Men类型的变量i</span>         <span style="color: #0000ff;">var</span> i Men          <span style="color: #008000;">//</span><span style="color: #008000;">i能存储Student</span>         i = mike　　　　         fmt.Println(<span style="color: #800000;">"</span><span style="color: #800000;">This is Mike, a Student:</span><span style="color: #800000;">"</span>)         i.SayHi()         i.Sing(<span style="color: #800000;">"</span><span style="color: #800000;">November rain</span><span style="color: #800000;">"</span>)          <span style="color: #008000;">//</span><span style="color: #008000;">i也能存储Employee</span>         i = tom         fmt.Println(<span style="color: #800000;">"</span><span style="color: #800000;">This is tom, an Employee:</span><span style="color: #800000;">"</span>)         i.SayHi()         i.Sing(<span style="color: #800000;">"</span><span style="color: #800000;">Born to be wild</span><span style="color: #800000;">"</span>)          <span style="color: #008000;">//</span><span style="color: #008000;">定义了slice Men</span>         fmt.Println(<span style="color: #800000;">"</span><span style="color: #800000;">Let's use a slice of Men and see what happens</span><span style="color: #800000;">"</span>)         x := make([]Men, <span style="color: #800080;">3</span>)         <span style="color: #008000;">//</span><span style="color: #008000;">这三个都是不同类型的元素，但是他们实现了interface同一个接口</span>         x[<span style="color: #800080;">0</span>], x[<span style="color: #800080;">1</span>], x[<span style="color: #800080;">2</span>] = paul, sam, mike          <span style="color: #0000ff;">for</span> _, value := range x{             value.SayHi()         }     }</pre> <div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div></div> <p>&nbsp;</p> <h3>空接口</h3> <p>空interface(interface{})不包含任何的method，正因为如此，<span style="background-color: #ffff00;">所有的类型都实现了空interface</span>。空interface对于描述起不到任何的作用(因为它不包含任何的method），但是<span style="background-color: #ffff00;">空interface在我们需要存储任意类型的数值的时候相当有用，因为它可以存储任意类型的数值。它有点类似于C语言的void*类型。</span></p> <div><div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div> <pre><span style="color: #008000;">//</span><span style="color: #008000;"> 定义a为空接口</span>     <span style="color: #0000ff;">var</span> a <span style="color: #0000ff;">interface</span>{}     <span style="color: #0000ff;">var</span> i <span style="color: #0000ff;">int</span> = <span style="color: #800080;">5</span>     s := <span style="color: #800000;">"</span><span style="color: #800000;">Hello world</span><span style="color: #800000;">"</span>     <span style="color: #008000;">//</span><span style="color: #008000;"> a可以存储任意类型的数值</span>     a = i     a = s</pre> <div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div></div> <p>&nbsp;</p> <p>interface的变量里面可以存储任意类型的数值（该类型实现了interface），那么我们怎么反向知道这个interface变量里面实际保存了的是哪个类型的对象呢？目前常用的有两种方法：switch测试、Comma-ok断言。</p> <p>&nbsp;</p> <p>switch测试如下：</p> <div><div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div> <pre>type Element <span style="color: #0000ff;">interface</span>{} type List [] Element  type Person <span style="color: #0000ff;">struct</span> {     name <span style="color: #0000ff;">string</span>     age <span style="color: #0000ff;">int</span>  }  <span style="color: #008000;">//</span><span style="color: #008000;">打印</span> func (p Person) String() <span style="color: #0000ff;">string</span> {     <span style="color: #0000ff;">return</span> <span style="color: #800000;">"</span><span style="color: #800000;">(name: </span><span style="color: #800000;">"</span> + p.name + <span style="color: #800000;">"</span><span style="color: #800000;"> - age: </span><span style="color: #800000;">"</span>+strconv.Itoa(p.age)+ <span style="color: #800000;">"</span><span style="color: #800000;"> years)</span><span style="color: #800000;">"</span> }  func main() {     list := make(List, <span style="color: #800080;">3</span>)     list[<span style="color: #800080;">0</span>] = <span style="color: #800080;">1</span> <span style="color: #008000;">//</span><span style="color: #008000;">an int </span>     list[<span style="color: #800080;">1</span>] = <span style="color: #800000;">"</span><span style="color: #800000;">Hello</span><span style="color: #800000;">"</span> <span style="color: #008000;">//</span><span style="color: #008000;">a string</span>     list[<span style="color: #800080;">2</span>] = Person{<span style="color: #800000;">"</span><span style="color: #800000;">Dennis</span><span style="color: #800000;">"</span>, <span style="color: #800080;">70</span>}       <span style="color: #0000ff;">for</span> index, element := range list{         <span style="color: #0000ff;">switch</span> value := element.(type) {             <span style="color: #0000ff;">case</span> <span style="color: #0000ff;">int</span>:                 fmt.Printf(<span style="color: #800000;">"</span><span style="color: #800000;">list[%d] is an int and its value is %d\n</span><span style="color: #800000;">"</span>, index, value)             <span style="color: #0000ff;">case</span> <span style="color: #0000ff;">string</span>:                 fmt.Printf(<span style="color: #800000;">"</span><span style="color: #800000;">list[%d] is a string and its value is %s\n</span><span style="color: #800000;">"</span>, index, value)             <span style="color: #0000ff;">case</span> Person:                 fmt.Printf(<span style="color: #800000;">"</span><span style="color: #800000;">list[%d] is a Person and its value is %s\n</span><span style="color: #800000;">"</span>, index, value)             <span style="color: #0000ff;">default</span>:                 fmt.Println(<span style="color: #800000;">"</span><span style="color: #800000;">list[%d] is of a different type</span><span style="color: #800000;">"</span>, index)         }        }    }</pre> <div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div></div> <p>&nbsp;</p> <p>如果使用Comma-ok断言的话：</p> <div><div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div> <pre>func main() {     list := make(List, <span style="color: #800080;">3</span>)     list[<span style="color: #800080;">0</span>] = <span style="color: #800080;">1</span> <span style="color: #008000;">//</span><span style="color: #008000;"> an int</span>     list[<span style="color: #800080;">1</span>] = <span style="color: #800000;">"</span><span style="color: #800000;">Hello</span><span style="color: #800000;">"</span> <span style="color: #008000;">//</span><span style="color: #008000;"> a string</span>     list[<span style="color: #800080;">2</span>] = Person{<span style="color: #800000;">"</span><span style="color: #800000;">Dennis</span><span style="color: #800000;">"</span>, <span style="color: #800080;">70</span>}      <span style="color: #0000ff;">for</span> index, element := range list {         <span style="color: #0000ff;">if</span> value, ok := element.(<span style="color: #0000ff;">int</span>); ok {             fmt.Printf(<span style="color: #800000;">"</span><span style="color: #800000;">list[%d] is an int and its value is %d\n</span><span style="color: #800000;">"</span>, index, value)         } <span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> value, ok := element.(<span style="color: #0000ff;">string</span>); ok {             fmt.Printf(<span style="color: #800000;">"</span><span style="color: #800000;">list[%d] is a string and its value is %s\n</span><span style="color: #800000;">"</span>, index, value)         } <span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> value, ok := element.(Person); ok {             fmt.Printf(<span style="color: #800000;">"</span><span style="color: #800000;">list[%d] is a Person and its value is %s\n</span><span style="color: #800000;">"</span>, index, value)         } <span style="color: #0000ff;">else</span> {             fmt.Printf(<span style="color: #800000;">"</span><span style="color: #800000;">list[%d] is of a different type\n</span><span style="color: #800000;">"</span>, index)         }     } }</pre> <div><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></div></div> <p>&nbsp;</p> <p>&nbsp;</p> <h3>嵌入接口</h3> <p>正如struct类型可以包含一个匿名字段，interface也可以嵌套另外一个接口。</p> <p>如果一个interface1作为interface2的一个嵌入字段，那么interface2隐式的包含了interface1里面的method。</p> <p>&nbsp;</p> <p>&nbsp;</p> <h3>反射</h3> <p>所谓反射（reflect）就是能检查程序在运行时的状态。</p> <p>使用reflect一般分成三步，下面简要的讲解一下：要去反射是一个类型的值(这些值都实现了空interface)，首先需要把它转化成reflect对象(reflect.Type或者reflect.Value，根据不同的情况调用不同的函数)。这两种获取方式如下：</p> <div> <pre> t := reflect.TypeOf(i)    <span style="color: #008000;">//</span><span style="color: #008000;">得到类型的元数据,通过t我们能获取类型定义里面的所有元素</span>  v := reflect.ValueOf(i)   <span style="color: #008000;">//</span><span style="color: #008000;">得到实际的值，通过v我们获取存储在里面的值，还可以去改变值</span></pre> </div> <p>&nbsp;</p> <p>转化为reflect对象之后我们就可以进行一些操作了，也就是将reflect对象转化成相应的值，例如</p> <div> <pre>tag := t.Elem().Field(<span style="color: #800080;">0</span>).Tag  <span style="color: #008000;">//</span><span style="color: #008000;">获取定义在struct里面的标签</span> name := v.Elem().Field(<span style="color: #800080;">0</span>).String()  <span style="color: #008000;">//</span><span style="color: #008000;">获取存储在第一个字段里面的值</span></pre> </div> <p>&nbsp;</p> <p>获取反射值能返回相应的类型和数值</p> <div> <pre><span style="color: #0000ff;">var</span> x float64 = <span style="color: #800080;">3.4</span> v := reflect.ValueOf(x) fmt.Println(<span style="color: #800000;">"</span><span style="color: #800000;">type:</span><span style="color: #800000;">"</span>, v.Type()) fmt.Println(<span style="color: #800000;">"</span><span style="color: #800000;">kind is float64:</span><span style="color: #800000;">"</span>, v.Kind() == reflect.Float64) fmt.Println(<span style="color: #800000;">"</span><span style="color: #800000;">value:</span><span style="color: #800000;">"</span>, v.Float())</pre> </div> <p>&nbsp;</p> <p>最后，反射的话，那么反射的字段必须是可修改的，我们前面学习过传值和传引用，这个里面也是一样的道理。反射的字段必须是可读写的意思是，如果下面这样写，那么会发生错误</p> <div> <pre><span style="color: #0000ff;">var</span> x float64 = <span style="color: #800080;">3.4</span> v := reflect.ValueOf(x) v.SetFloat(<span style="color: #800080;">7.1</span>)</pre> </div> <p>&nbsp;</p> <p>如果要修改相应的值，必须这样写</p> <div> <pre><span style="color: #0000ff;">var</span> x float64 = <span style="color: #800080;">3.4</span> p := reflect.ValueOf(&amp;x) v := p.Elem() v.SetFloat(<span style="color: #800080;">7.1</span>)</pre> </div> <p>上面只是对反射的简单介绍，更深入的理解还需要自己在编程中不断的实践。</p> <p>&nbsp;</p> <p>&nbsp;</p> <p><strong>参考文档：</strong></p> <p><a href="http://se77en.cc/2014/05/05/methods-interfaces-and-embedded-types-in-golang/" target="_blank">http://se77en.cc/2014/05/05/methods-interfaces-and-embedded-types-in-golang/</a></p> <p><a href="http://se77en.cc/2014/05/04/choose-whether-to-use-a-value-or-pointer-receiver-on-methods/" target="_blank">http://se77en.cc/2014/05/04/choose-whether-to-use-a-value-or-pointer-receiver-on-methods/<br /></a></p> <p>&nbsp;http://www.cnblogs.com/chenny7/p/4497969.html<br /><br /><br /><br /></p><p><br /><br /></p><img src ="http://www.blogjava.net/stevenjohn/aggbug/432720.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/stevenjohn/" target="_blank">abin</a> 2017-08-03 11:34 <a href="http://www.blogjava.net/stevenjohn/archive/2017/08/03/432720.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>老虞要学GoLang-函数(上)</title><link>http://www.blogjava.net/stevenjohn/archive/2017/08/02/432718.html</link><dc:creator>abin</dc:creator><author>abin</author><pubDate>Wed, 02 Aug 2017 08:39:00 GMT</pubDate><guid>http://www.blogjava.net/stevenjohn/archive/2017/08/02/432718.html</guid><wfw:comment>http://www.blogjava.net/stevenjohn/comments/432718.html</wfw:comment><comments>http://www.blogjava.net/stevenjohn/archive/2017/08/02/432718.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/stevenjohn/comments/commentRss/432718.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/stevenjohn/services/trackbacks/432718.html</trackback:ping><description><![CDATA[<p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">不可或缺的函数，在Go中定义函数的方式如下：</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">func (p myType ) funcName ( a, b int , c string ) ( r , s int ) {     return } </code></pre><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">通过函数定义，我们可以看到Go中函数和其他语言中的共性和特性</p><h3><a name="-1" href="http://www.cnblogs.com/howDo/archive/2013/06/04/GoLang-function.html#-1" style="margin: 0px 0px 0px -30px; padding: 1px 3px 1px 30px; color: green; text-decoration: none; display: block; cursor: pointer; position: absolute; top: 0px; left: 0px; bottom: 0px;"></a>共性</h3><ul style="margin: 15px 0px 15px 30px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;"><li style="margin: 0px; padding: 0px; list-style: disc;">关键字&#8212;&#8212;func</li><li style="margin: 0px; padding: 0px; list-style: disc;">方法名&#8212;&#8212;funcName</li><li style="margin: 0px; padding: 0px; list-style: disc;">入参&#8212;&#8212;&#8212; a,b int,b string</li><li style="margin: 0px; padding: 0px; list-style: disc;">返回值&#8212;&#8212; r,s int</li><li style="margin: 0px; padding: 0px; list-style: disc;">函数体&#8212;&#8212; {}</li></ul><h3><a name="-2" href="http://www.cnblogs.com/howDo/archive/2013/06/04/GoLang-function.html#-2" style="margin: 0px 0px 0px -30px; padding: 1px 3px 1px 30px; color: green; text-decoration: none; display: block; cursor: pointer; position: absolute; top: 0px; left: 0px; bottom: 0px;"></a>特性</h3><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">Go中函数的特性是非常酷的，给我们带来不一样的编程体验。</p><h4><a name="-3" href="http://www.cnblogs.com/howDo/archive/2013/06/04/GoLang-function.html#-3" style="margin: 0px 0px 0px -30px; padding: 1px 3px 1px 30px; color: green; text-decoration: none; display: block; cursor: pointer; position: absolute; top: 0px; left: 0px; bottom: 0px;"></a>为特定类型定义函数，即为类型对象定义方法</h4><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">在Go中通过给函数标明所属类型，来给该类型定义方法，上面的&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; white-space: nowrap; font-family: monospace, Monaco;">p myType</code>&nbsp;即表示给myType声明了一个方法，&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; white-space: nowrap; font-family: monospace, Monaco;">p myType</code>&nbsp;不是必须的。如果没有，则纯粹是一个函数，通过包名称访问。packageName.funcationName</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">如：</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">//定义新的类型double，主要目的是给float64类型扩充方法 type double float64  //判断a是否等于b func (a double) IsEqual(b double) bool {     var r = a - b     if r == 0.0 {         return true     } else if r &lt; 0.0 {         return r &gt; -0.0001     }     return r &lt; 0.0001 }  //判断a是否等于b func IsEqual(a, b float64) bool {     var r = a - b     if r == 0.0 {         return true     } else if r &lt; 0.0 {         return r &gt; -0.0001     }     return r &lt; 0.0001 }  func main() {     var a double = 1.999999     var b double = 1.9999998     fmt.Println(a.IsEqual(b))     fmt.Println(a.IsEqual(3))     fmt.Println( IsEqual( (float64)(a), (float64)(b) ) )  } </code></pre><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">上述示例为 float64 基本类型扩充了方法IsEqual，该方法主要是解决精度问题。 其方法调用方式为：&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; white-space: nowrap; font-family: monospace, Monaco;">a.IsEqual(double)</code>&nbsp;，如果不扩充方法，我们只能使用函数<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; white-space: nowrap; font-family: monospace, Monaco;">IsEqual(a, b float64)</code></p><h4><a name="-4" href="http://www.cnblogs.com/howDo/archive/2013/06/04/GoLang-function.html#-4" style="margin: 0px 0px 0px -30px; padding: 1px 3px 1px 30px; color: green; text-decoration: none; display: block; cursor: pointer; position: absolute; top: 0px; left: 0px; bottom: 0px;"></a>入参中，如果连续的参数类型一致，则可以省略连续多个参数的类型，只保留最后一个类型声明。</h4><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">如&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; white-space: nowrap; font-family: monospace, Monaco;">func IsEqual(a, b float64) bool</code>&nbsp;这个方法就只保留了一个类型声明,此时入参a和b均是float64数据类型。 这样也是可以的：&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; white-space: nowrap; font-family: monospace, Monaco;">func IsEqual(a, b float64, accuracy int) bool</code></p><h4><a name="-5" href="http://www.cnblogs.com/howDo/archive/2013/06/04/GoLang-function.html#-5" style="margin: 0px 0px 0px -30px; padding: 1px 3px 1px 30px; color: green; text-decoration: none; display: block; cursor: pointer; position: absolute; top: 0px; left: 0px; bottom: 0px;"></a>变参：入参支持变参,即可接受不确定数量的同一类型的参数</h4><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">如&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; white-space: nowrap; font-family: monospace, Monaco;">func Sum(args ...int)</code>&nbsp;参数args是的slice，其元素类型为int 。经常使用的fmt.Printf就是一个接受任意个数参数的函数&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; white-space: nowrap; font-family: monospace, Monaco;">fmt.Printf(format string, args ...interface{})</code></p><h4><a name="-6" href="http://www.cnblogs.com/howDo/archive/2013/06/04/GoLang-function.html#-6" style="margin: 0px 0px 0px -30px; padding: 1px 3px 1px 30px; color: green; text-decoration: none; display: block; cursor: pointer; position: absolute; top: 0px; left: 0px; bottom: 0px;"></a>支持多返回值</h4><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">前面我们定义函数时返回值有两个r,s 。这是非常有用的，我在写C#代码时，常常为了从已有函数中获得更多的信息，需要修改函数签名，使用out ,ref 等方式去获得更多返回结果。而现在使用Go时则很简单，直接在返回值后面添加返回参数即可。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">如,在C#中一个字符串转换为int类型时逻辑代码</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">int v=0;  if ( int.TryPase("123456",out v) ) {     //code } </code></pre><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">而在Go中，则可以这样实现,逻辑精简而明确</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">if v,isOk :=int.TryPase("123456") ; isOk {     //code } </code></pre><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">同时在Go中很多函数充分利用了多返回值</p><ul style="margin: 15px 0px 15px 30px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;"><li style="margin: 0px; padding: 0px; list-style: disc;">func (file *File) Write(b []byte) (n int, err error)</li><li style="margin: 0px; padding: 0px; list-style: disc;">func Sincos(x float64) (sin, cos float64)</li></ul><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">那么如果我只需要某一个返回值，而不关心其他返回值的话，我该如何办呢？ 这时可以简单的使用符号下划线&#8221;_&#8220; 来忽略不关心的返回值。如：</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">_, cos = math.Sincos(3.1415) //只需要cos计算的值 </code></pre><h4><a name="-7" href="http://www.cnblogs.com/howDo/archive/2013/06/04/GoLang-function.html#-7" style="margin: 0px 0px 0px -30px; padding: 1px 3px 1px 30px; color: green; text-decoration: none; display: block; cursor: pointer; position: absolute; top: 0px; left: 0px; bottom: 0px;"></a>命名返回值</h4><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">前面我们说了函数可以有多个返回值，这里我还要说的是，在函数定义时可以给所有的返回值分别命名，这样就能在函数中任意位置给不同返回值复制，而不需要在return语句中才指定返回值。同时也能增强可读性，也提高godoc所生成文档的可读性</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">如果不支持命名返回值，我可能会是这样做的</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">func ReadFull(r Reader, buf []byte) (int, error) {     var n int     var err error      for len(buf) &gt; 0  {         var nr int         nr, err = r.Read(buf)          n += nr         if err !=nil {             return n,err         }         buf = buf[nr:]     }     return n,err } </code></pre><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">但支持给返回值命名后，实际上就是省略了变量的声明，return时无需写成<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; white-space: nowrap; font-family: monospace, Monaco;">return n,err</code>&nbsp;而是将直接将值返回</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">func ReadFull(r Reader, buf []byte) (n int, err error) {     for len(buf) &gt; 0 &amp;&amp; err == nil {         var nr int         nr, err = r.Read(buf)         n += nr         buf = buf[nr:]     }     return } </code></pre><h4><a name="-8" href="http://www.cnblogs.com/howDo/archive/2013/06/04/GoLang-function.html#-8" style="margin: 0px 0px 0px -30px; padding: 1px 3px 1px 30px; color: green; text-decoration: none; display: block; cursor: pointer; position: absolute; top: 0px; left: 0px; bottom: 0px;"></a>函数也是&#8220;值&#8221;</h4><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">和Go中其他东西一样，函数也是值，这样就可以声明一个函数类型的变量，将函数作为参数传递。</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">声明函数为值的变量(匿名函数:可赋值个变量，也可直接执行)</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">//赋值 fc := func(msg string) {     fmt.Println("you say :", msg) } fmt.Printf("%T \n", fc) fc("hello,my love") //直接执行 func(msg string) {     fmt.Println("say :", msg) }("I love to code") </code></pre><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">输出结果如下，这里表明fc 的类型为：func(string)</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">func(string)  you say : hello,my love say : I love to code </code></pre><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">将函数作为入参（回调函数），能带来便利。如日志处理，为了统一处理，将信息均通过指定函数去记录日志，且是否记录日志还有开关</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">func Log(title string, getMsg func() string) {     //如果开启日志记录,则记录日志     if true {         fmt.Println(title, ":", getMsg())     } } //---------调用-------------- count := 0 msg := func() string {     count++     return "您没有即使提醒我,已触犯法律" } Log("error", msg) Log("warring", msg) Log("info", msg) fmt.Println(count) </code></pre><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">这里输出结果如下，count 也发生了变化</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">error : 您没有即使提醒我,已触犯法律 warring : 您没有即使提醒我,已触犯法律 info : 您没有即使提醒我,已触犯法律 3 </code></pre><h4><a name="-9" href="http://www.cnblogs.com/howDo/archive/2013/06/04/GoLang-function.html#-9" style="margin: 0px 0px 0px -30px; padding: 1px 3px 1px 30px; color: green; text-decoration: none; display: block; cursor: pointer; position: absolute; top: 0px; left: 0px; bottom: 0px;"></a>函数也是&#8220;类型&#8221;</h4><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">你有没有注意到上面示例中的&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; white-space: nowrap; font-family: monospace, Monaco;">fc := func(msg string)...</code>&nbsp;，既然匿名函数可以赋值给一个变量，同时我们经常这样给int赋值&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; white-space: nowrap; font-family: monospace, Monaco;">value := 2</code>&nbsp;,是否我们可以声明func(string) 类型 呢，当然是可以的。</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">//一个记录日志的类型：func(string) type saveLog func(msg string)  //将字符串转换为int64,如果转换失败调用saveLog func stringToInt(s string, log saveLog) int64 {      if value, err := strconv.ParseInt(s, 0, 0); err != nil {         log(err.Error())         return 0     } else {         return value     } }  //记录日志消息的具体实现 func myLog(msg string) {     fmt.Println("Find Error:", msg) }  func main() {     stringToInt("123", myLog) //转换时将调用mylog记录日志     stringToInt("s", myLog) } </code></pre><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">这里我们定义了一个类型，专门用作记录日志的标准接口。在stringToInt函数中如果转换失败则调用我自己定义的接口函数进行日志处理，至于最终执行的哪个函数，则无需关心。</p><h4><a name="defer-" href="http://www.cnblogs.com/howDo/archive/2013/06/04/GoLang-function.html#defer-" style="margin: 0px 0px 0px -30px; padding: 1px 3px 1px 30px; color: green; text-decoration: none; display: block; cursor: pointer; position: absolute; top: 0px; left: 0px; bottom: 0px;"></a>defer 延迟函数</h4><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">defer 又是一个创新，它的作用是：延迟执行，在声明时不会立即执行，而是在函数return后时按照后进先出的原则依次执行每一个defer。这样带来的好处是，能确保我们定义的函数能百分之百能够被执行到，这样就能做很多我们想做的事，如释放资源，清理数据，记录日志等</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">这里我们重点来说明下defer的执行顺序</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">func deferFunc() int {     index := 0      fc := func() {          fmt.Println(index, "匿名函数1")         index++          defer func() {             fmt.Println(index, "匿名函数1-1")             index++         }()     }      defer func() {         fmt.Println(index, "匿名函数2")         index++     }()      defer fc()      return func() int {         fmt.Println(index, "匿名函数3")         index++         return index     }() }  func main() {     deferFunc() } </code></pre><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">这里输出结果如下，</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">0 匿名函数3 1 匿名函数1 2 匿名函数1-1 3 匿名函数2 </code></pre><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">有如下结论：</p><ul style="margin: 15px 0px 15px 30px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;"><li style="margin: 0px; padding: 0px; list-style: disc;">defer 是在执行完return 后执行</li><li style="margin: 0px; padding: 0px; list-style: disc;">defer 后进先执行</li></ul><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">另外，我们常使用defer去关闭IO,在正常打开文件后，就立刻声明一个defer，这样就不会忘记关闭文件，也能保证在出现异常等不可预料的情况下也能关闭文件。而不像其他语言：<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; white-space: nowrap; font-family: monospace, Monaco;">try-catch</code>&nbsp;或者&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; white-space: nowrap; font-family: monospace, Monaco;">using()</code>&nbsp;方式进行处理。</p><pre style="margin: 15px; padding: 6px 10px; white-space: pre-wrap; word-wrap: break-word; background: #141414; border: 1px solid #cccccc; font-size: 13px; line-height: 19px; overflow: auto; border-radius: 3px; color: #f2f2f2;"><code style="margin: 0px; padding: 0px; border: none; background: transparent; border-radius: 3px; white-space: pre; font-size: 14px; font-family: monospace, Monaco;">file , err :=os.Open(file) if err != nil {     return err } defer file.Close()  //dosomething with file </code></pre><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">后续，我将讨论： 作用域、传值和传指针 以及 保留函数init(),main()</p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;">本笔记中所写代码存储位置：</p><ul style="margin: 15px 0px 15px 30px; padding: 0px; font-family: Verdana, Arial, Helvetica, sans-serif; background-color: #ffffff;"><li style="margin: 0px; padding: 0px; list-style: disc;"><a href="https://github.com/devYu/GoLangStudy/tree/master/codeDemo/defer.go" style="margin: 0px; padding: 1px 3px; color: green; text-decoration: none;">defer.go</a></li><li style="margin: 0px; padding: 0px; list-style: disc;"><a href="https://github.com/devYu/GoLangStudy/tree/master/codeDemo/defineFunctionType.go" style="margin: 0px; padding: 1px 3px; color: green; text-decoration: none;">defineFunctionType.go</a></li><li style="margin: 0px; padding: 0px; list-style: disc;"><a href="https://github.com/devYu/GoLangStudy/tree/master/codeDemo/function.go" style="margin: 0px; padding: 1px 3px; color: green; text-decoration: none;">function.go<br /><br /><br /><br /><div>http://www.cnblogs.com/howDo/archive/2013/06/04/GoLang-function.html</div><br /></a></li></ul><img src ="http://www.blogjava.net/stevenjohn/aggbug/432718.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/stevenjohn/" target="_blank">abin</a> 2017-08-02 16:39 <a href="http://www.blogjava.net/stevenjohn/archive/2017/08/02/432718.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>