zoukankan      html  css  js  c++  java
  • 9.6Go之函数之可变参数

    9.6Go之函数之可变参数

    可变参数的概念

    概念:

    可变参数是指:

    • 传入的参数类型可变

    • 传入的参数数量可变

    传入参数数量可变

    特点:

    • 以切片举例,通常我们指传入参数的值的数量可变

    • 在Go语言中提供了一种语法糖(syntactic sugar)...type这种语法对语言的功能并没有影响,能够增加程序的可读性,减少程序出错的可能。

      • 类型...type本质上是一个数组切片,也就是[]type,所以参数 args 可以用 for 循环来获得每个传入的参数。

    示例:

    package main

    import "fmt"

    func getValue(args ...int) {
    for _, v := range args {
    fmt.Printf("value is:%d ", v)
    }
    /*
    这里的形参带了...会自动将数据类型转为数组类型使用切片的方式进行接收和打印
    */
    }

    /*
    如果没有...的语法糖那么在实现的时候需要这样写
    */
    func getValue2(args []int) {
    for _, v := range args {
    fmt.Printf("Value is:%d ", v)
    }
    }

    func main() {
    getValue(1,2,3,4,5)
       fmt.Println("##########")
    //调用的时候传入的参数就必须是数组切片
    getValue2([]int{5,4,3,2,1})
    }

    通常这种情况用于接收相同类型的参数,由于可变参数列表的数量不固定,传入的参数是一个切片,如果需要获得每一个参数的具体值时:

    • 对可变参数变量进行遍历

    • 将可变参数的内容进行拼接

    使用bytes包下封装好的方法--->主要用到BufferWriteStringString方法

    示例:

    package main

    import (
    "bytes"
    "fmt"
    )

    func jointString(slist ...string) string {
    //定义变量--->这个变量相当于字符串拼接完成后的值--->这是一个字节数组
    var b bytes.Buffer //Buffer是一个结构体,创建字节数组类型的变量

    //循环获取形参数组里面的内容
    for _, v := range slist {
    //将遍历出的字符串连续写入字节数组
    b.WriteString(v) //将每一个传入参数放到 bytes.Buffer 中
    }

    return b.String() //传入字节数组的指针,返回拼接后的字符串值
    }

    func main() {
    //连续输入字符将它们拼接成一个字符串
    fmt.Println(jointString("Jun", "is", "a", "handsome", "boy!"))
    }
    /*
    要获取可变参数的数量,使用 len() 函数对可变参数变量对应的切求长度,获得可变参数数量
    */

    传入参数类型、数量均可变

    特点:

    • 要使传入参数的类型、数量均可变则需要采用interface{}

    • Go语言标准库中 fmt.Printf() 的函数原型:

      • func Printf(format string, args ...interface{}) {
           // ...
        }
        /*
        使用interface{}是类型安全的
        */

    示例:

    package main

    import "fmt"

    func parameters(args ...interface{}) {
    for _, v := range args {
    switch v.(type) {
    case string:
    fmt.Printf("Value is:%s ", v)
    case int:
    fmt.Printf("Value is:%d ", v)
    case float32:
    fmt.Printf("Value is:%f ", v)
    case float64:
    fmt.Printf("Value is:%f", v)
    default:
    fmt.Println("Unknow type!!!")
    }
    }
       /*
       首先:
       1、interface{}前必须+"...",否则会认为是单个值,不能进行循环
       2、switch的内容是v变量,该变量被声明为interface{}当中的每一个值
       3、通过.type类型去判断里面的值的类型然后进行相应的处理
       4、由进行的匿名循环看出,这些类型被内置定义成了一个类似切片的类型,所以才可以进行匿名循环
       */
       /*
       Go语言中的interface{}又比Java当中的inteface强大了很多。
       Java当中的interface是一个类型,能接收的对象是实现了该接口的类的对象
       Go当中的interface则不是
       */
    }

    func main() {
    parameters(1,"JunkingBoy",3.1415)
    }
    /*
    在传递参数的时候可以传递任意类型的参数
    */

    由于上诉操作可变参数为 interface{} 类型,可以传入任何类型的值,下面将这些内容拼接成字符串并且打印出来:

    package main

    import (
    "bytes"
    "fmt"
    )

    func printTypeValue(slist ...interface{}) string {
    //定义字节数组
    var b bytes.Buffer
    //定义一个描述类型的字符串
    var valueType string

    //循环获取interface{}当中的值
    for _, s := range slist {
    //定义一个写入的值的变量
    str := fmt.Sprintf("%v", s) //注意这个方法是Sprintf不是Printf
           /*
           使用 fmt.Sprintf 配合%v动词,可以将 interface{} 格式的任意值转为字符串
           */
    //判断值的类型
    switch s.(type) {
    case bool:
    valueType = "bool"
    case int:
    valueType = "int"
    case string:
    valueType = "string"
    default:
    fmt.Println("Unknow value type!")
    }
           /*
           switch s.(type) 可以对 interface{} 类型进行类型断言,判断变量的实际类型
           */

    //分别写入字符串前缀、值、类型
    b.WriteString("value is:")
    b.WriteString(str + " ")
    b.WriteString("type:")
    b.WriteString(valueType)
    b.WriteString(" ")
    }

    return b.String()
    }

    func main() {
    fmt.Println(printTypeValue(100, "JunkingBoy", false))
    }

    在多个可变参数函数中传递参数--->将可变参数整体传递给下一个可变参数函数

    特点:

    • 可变参数变量是一个包含所有参数的切片,要将这个含有可变参数的变量传递给下一个可变参数函数,在传递时给可变参数变量后面添加...,就可以将切片中的元素进行传递,而不是传递可变参数变量本身。

    • 传递可变参数中每一个参数元素本身而不是可变参数这个变量--->非常重要

    示例:--->创建两个函数,将第二个函数的形参完整的传递给第一个函数,在第二个函数里面调用第一个函数(有点类似闭包但是却不是)

    package main

    import "fmt"

    /*
    第一个函数
    */
    func rawPrint(slist ...interface{}) {
    //遍历切片
    for _, v := range slist {
    //打印参数
    fmt.Println(v)
    }
    }

    /*
    第二个函数,在内部调用第一个函数
    */
    func print(slist ...interface{}) {
    //将传入的形参元素完整的传递给第一个函数
    rawPrint(slist...) //将变量在 print 的可变参数列表中添加...后传递给 rawPrint()。
       /*
       这个时候通过打印的结果可以看出slist类型不是作为一个整体传入rawPrint当中,而是逐个元素传入
       */
       rawPrint("fmt", slist) //此时,slist(类型为 []interface{})将被作为一个整体传入 rawPrint(),rawPrint() 函数中遍历的变量也就是 slist 的切片值。

    }

    func main() {
    //外部调用第二个函数
    print(1, "JunkingBoy", 2)
    }

    可变参数使用...进行传递与切片间使用 append 连接是同一个特性。

    It's a lonely road!!!
  • 相关阅读:
    Centos7安装Python3的方法
    word2vec原理(二) 基于Hierarchical Softmax的模型
    word2vec原理(一) CBOW与Skip-Gram模型基础
    爬虫的危害有多大
    python线程池实现
    进程和线程、协程的区别
    程序的编译与解释之间的区别
    【python3】如何建立爬虫代理ip池
    可能是史上最全的机器学习和Python(包括数学)速查表
    python 元类
  • 原文地址:https://www.cnblogs.com/JunkingBoy/p/15235301.html
Copyright © 2011-2022 走看看