zoukankan      html  css  js  c++  java
  • [Go语言]从Docker源码学习Go——function和method

    function和method关系

    method是针对某一类型定义的function,

    function可以单独调用,method必须针对某一类型的实例进行调用

    //function 调用方式
    packageName.FuncName()
    
    //method 调用方式
    var t packageName.Type
    t.MethodName()

    源码

    func (cli *DockerCli) LoadConfigFile() (err error) {
        cli.configFile, err = registry.LoadConfig(os.Getenv("HOME"))
        if err != nil {
            fmt.Fprintf(cli.err, "WARNING: %s
    ", err)
        }
        return err
    }
    
    func NewDockerCli(in io.ReadCloser, out, err io.Writer, proto, addr string, tlsConfig *tls.Config) *DockerCli {
        ...
        return &DockerCli{
            proto:      proto,
            addr:       addr,
            in:         in,
            out:        out,
                    ...
        }
    }

    LoadConfigFile()是method,而NewDockerCli()是function。

    Function

    func functionName(parameter_list) (return_value_list) {
    …
    }
    //parameter_list form (param1 type1, param2 type2, …)
    //return_value_list form (ret1 type1, ret2 type2, …)

    注:function可以返回多个参数,如果在调用时不想接受某个参数,使用下划线_

    _, exist = FunctionName(...)

    值/引用传递的问题

    默认情况下,function中的参数是进行值传递的,如果想要在function内部修改原来数据的值,需要传递引用,用&符号。

    例外:引用类型默认是进行引用传递的,比如slices, maps, interfaces, channels.

    func ChangeValue(value *Struct1, newValue int) {
        value.Int1 = newValue
    }
    
    func NotChangeValue(value Struct1, newValue int) {
        value2 := &value
        value2.Int1 = newValue
    }

    可以通过定义最后一个参数的类型为...Type来传递多个同一类型的多个参数

    func Min(ints ...int) int {
    //ints类型为[]int{},值是传递进来的值。
    if len(ints) == 0 { return -1 } min := ints[0] for _, x := range ints { if x < min { min = x } } return min } //调用 fmt.Println(Min(4, 6, 9, 10, 3, 2)) arr := []int{9, 5, 3, 10, 20, 2} fmt.Println(Min(arr...))

    上面介绍的是传入多个相同类型的情况,那如果不同类型的多个怎么定义呢?

    有两种方法,第一种是通过定义一个新的struct,包含这些不同的类型,然后把这个struct类型作为输入参数;第二种是使用空的Interface。

    主要介绍第二种

    func PrintType(variables ...interface{}) {
        for _, v := range variables {
            switch v.(type) {
            case int:
                fmt.Println("type is int %d", v)
            default:
                fmt.Println("other type %v", v)
            }
        }
    }
    
    func showFunctionMultiInterfaceParameters() {
        lemon.PrintType(5, "aaaa")
        var2 := []interface{}{6, 7, 9, "bbb", "ccc"}
        lemon.PrintType(var2...)
    }

    注:需要在方法内部判断类型,之后进行操作。

    defer

    defer用来定义在方法最后执行的语句,在return后,}之前。

    注意:在同一个方法中先后定义两个defer,执行顺序是倒序的,LIFO.

    func DeferOrder() {
        for i := 0; i < 4; i++ {
            defer fmt.Println("index value is %d", i)
        }
    }
    //输出
    index value is %d 3
    index value is %d 2
    index value is %d 1
    index value is %d 0

    method

    method是特殊的function,定义在某一特定的类型上,通过类型的实例来进行调用,这个实例被叫receiver。

    receiver类型可以是任意类型,包括function类型,但是,receiver不能是interface类型。

    func (recv receiver_type) methodName(parameter_list) (return_value_list) {...}

    注:method和它的类型必须定义在一个包内!但是我们可以通过其它的方式来实现。

    解决思路:怎么样可以让原来的类型在我们自己的包中定义呢?

    两种方法:

    第一种,通过alias。

    type Int int

    这样在对Int进行方法定义。

    第二种,通过匿名属性

    type Int struct{
        int
    }

    两种方法,第二种比较好,因为第一种只针对当前的alias有用,重用性不如第二种方法好。

    如果想要在method内部修改receiver的属性值,recv *receiver_type(在type前面增加一个*),表示传入引用。

    此时传入值也没关系,go语言自动实现转化,t.Func转换为(&t).Func.

    func (b *B) change(){...}
    
    var b1 B
    b1.change()

    总结

    go语言中把method和type分开进行定义。

    好处是我们可以为任何类型增加方法,而不用去修改原来的代码。

  • 相关阅读:
    java
    java
    Java hashCode() 和 equals()
    Python可变参数*和**
    Hadoop Mapreduce分区、分组、二次排序
    Java 内部类
    java valueOf()函数
    java接口和抽象类
    Java instanceof运算符
    JAVA ==号和equals()的区别
  • 原文地址:https://www.cnblogs.com/lemonbar/p/3932981.html
Copyright © 2011-2022 走看看