zoukankan      html  css  js  c++  java
  • 入门go语言(一)

    1、变量与常量

    1.1、变量声明

    • 第一种,指定变量类型,如果没有初始化,则变量默认为零值

    var num int
    num = 5
    
    • 第二种,根据值自行判定变量类型
    var name = "阿凡达"
    • 第三种,省略var,使用:=,:=左边必须是新定义的变量,否则报错
    f := 0.0043
    • 多变量声明
    var a,b,c = 1,2,3
    d,e,f := 4,5,6
    

    1.2、常量

    常量是一个简单值的标识符,在程序运行时,不会被修改的量。

    常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。

    • 声明
    const PI = 3.14159
    • iota

    iota,特殊常量,可以认为是一个可以被编译器修改的常量。

    iota 在 const关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行常量声明将使 iota 计数一次(iota 可理解为 const 语句块中的行索引)。

    const (
    	A = iota  // iota=0	A=0
    	B         // iota=1	B=1
    	C         // iota=2	C=2
    	D = "sky" // iota=3	D="sky"
    	E         // iota=4	E="sky"
    	F = 39    // iota=5	F=39
    	G = iota  // iota=6	G=6
    	H         // iota=7	H=7
    )
    
    const (
    	J = iota // iota=0	J=0
    )
    

    2、流程结构

    2.1、if 语句

    package main
    
    import "fmt"
    
    func main() {
    	var num int
    	fmt.Print("请输入 num 的值:")
    	fmt.Scanln(&num)
    	if num >= 5 {
    		fmt.Println("num 大于等于5.")
    	} else if num <= 0 {
    		fmt.Println("num 小于等于0.")
    	} else {
    		fmt.Println("num 大于 0 小于 5.")
    	}
    }
    

    2.2、switch 语句

    switch 语句用于基于不同条件执行不同动作,每一个 case 分支都是唯一的,从上至下逐一测试,直到匹配为止。

    switch 语句执行的过程从上至下,直到找到匹配项,匹配项后面也不需要再加 break。

    switch 默认情况下 case 最后自带 break 语句,匹配成功后就不会执行其他 case,如果我们需要执行后面的 case,可以使用 fallthrough 。

    语法:

    switch var1 {
        case val1:
            ...
        case val2:
            ...
        default:
            ...
    }
    

    2.3、for 循环

    语法

    Go 语言的 For 循环有 3 种形式,只有其中的一种使用分号。

    和 C 语言的 for 一样(1、先执行init,2、再判断 init 是否满足 condition 条件,3、执行循环体,4、执行 post ,给变量增值或减值):

    for init; condition; post { 循环体 }

    和 C 的 while 一样:

    for condition { }

    和 C 的 for(;;) 一样:

    for { }
    

    EXAMPLE:

    //打印九九乘法表
    func main() { for i := 1; i <= 9; i++ { for j := 1; j <= i; j++ { fmt.Printf("%d * %d = %d ", j, i, i*j) } fmt.Println() } }

     

    3、数组

    数组是存储一组数据类型相同且长度固定的数据序列。

    3.1、声明数组

    语法:var variable_name [SIZE] variable_type

    var num_array [5]int
    

    3.2、初始化数组

    // 定义和赋值放一起 [size]表示数组的长度,[...]表示不指定数组长度,长度由赋值的长度自动推导
    var num_array2 = [6]int{0, 1, 2, 3, 4, 5} var string_array = [...]string{"one", "two", "three", "four", "five", "six"}

    3.3、访问数组元素

    语法:array_name[index]

    3.4、数组是值类型

    package main
    
    /*
    1、值类型,赋值的时候,传递的是值的副本
    	int,float,string,array
    2、引用类型,赋值的时候,传递的是内存地址
    	slice,map
    
    数组的类型:[size]type
    [6]int
    [6]int
    [6]string
    
    */
    
    import "fmt"
    
    func main() {
    	array1 := [6]int{0, 1, 2, 3, 4, 5}
    	array2 := [6]int{0, 1, 2, 3, 4, 5}
    	array3 := [...]string{"one", "two", "three", "four", "five", "six"}
    
    	// 数组的类型
    	fmt.Printf("%T
    ", array1) //[6]int
    	fmt.Printf("%T
    ", array2) //[6]int
    	fmt.Printf("%T
    ", array3) //[6]string
    
    	// 数组是值类型
    	array4 := array1
    	fmt.Println(array1) //[0 1 2 3 4 5]
    	fmt.Println(array4) //[0 1 2 3 4 5]
    	// array1的改变不会影响到array4,说明数组是值类型
    	array1[0] = 10
    	fmt.Println(array1) //[10 1 2 3 4 5]
    	fmt.Println(array4) //[0 1 2 3 4 5]
    
    	// 值类型比较的是值是否一样
    	fmt.Println(array1 == array2) // false
    	array1[0] = 0
    	fmt.Println(array1 == array2) // true
    }

     3.5、切片

    package main
    
    /*
    slice就是不定长的数组
    
    slice的两种定义方式:
    1、 s1 := []int{}
    []中不填数组的长度,{}中可填数据,也可不填
    []type{}中间,则填要存储数据的类型,如 int,string,map[int]string
    
    2、 s2 := make([]int, 0, 8)
    通过内置函数make,make专门用来创建引用类型数据
    
    slice的值存储的是内存地址
    */
    
    import "fmt"
    
    func main() {
       s1 := []int{}
       s2 := make([]int, 4, 8)
       fmt.Println(s1) // []
       fmt.Println(s2) // [0 0 0 0]
    
       //使用 append 内置函数像 slice 中添加数据
       fmt.Printf("s1 的内存地址是:%p;存储的值的内存地址是:%p
    ", &s1, s1)
       s1 = append(s1, 1, 2, 3, 4)
       fmt.Printf("添加数值后 s1 的内存地址是:%p;存储的值的内存地址是:%p
    ", &s1, s1)
    
    }
    

      

    3.6、深浅拷贝

    package main
    
    /*
    1、深拷贝是值类型之间的拷贝,拷贝的是数值
    2、浅拷贝是引用类型之间的拷贝,拷贝的是内存地址
    
    copy(dst, src)函数:
    相当于
    for i:=0;i<len(dst);i++ {
    	dst[i]=src[i]
    }
    当然,也可使用切片,指定复制和粘贴的位置,如:
    dst[2:]		从2的索引开始粘贴,直到结束
    src[4:6]	复制索引4到6的数值
    */
    
    import "fmt"
    
    func main() {
    	s1 := []int{0, 1, 2, 3, 4}
    
    	//浅拷贝
    	//s1 的内存地址是:0xc00005a420,s1 的底层数组的内存地址是:0xc00008e030
    	//s2 的内存地址是:0xc00005a480,s2 的底层数组的内存地址是:0xc00008e030
    	//可以看到,s1和s2的存储的底层数组的内存地址是一样的,这就是浅拷贝
    	fmt.Printf("s1 的内存地址是:%p,s1 的底层数组的内存地址是:%p,s1 的值是:%d
    ", &s1, s1, s1)
    	s2 := s1
    	fmt.Printf("s2 的内存地址是:%p,s2 的底层数组的内存地址是:%p,s2 的值是:%d
    ", &s2, s2, s2)
    
    	fmt.Println("*****************************************************************")
    
    	//深拷贝
    	//s1 的内存地址是:0xc000004460,s1 的底层数组的内存地址是:0xc00000e360
    	//s3 的内存地址是:0xc000004580,s3 的底层数组的内存地址是:0xc00000e390
    	//可以看到,s1和s2的存储的底层数组的内存地址是不一样的,这就是深拷贝
    	fmt.Printf("s1 的内存地址是:%p,s1 的底层数组的内存地址是:%p,s1 的值是:%d
    ", &s1, s1, s1)
    	s3 := make([]int, 5, 5)
    	copy(s3, s1)
    	fmt.Printf("s3 的内存地址是:%p,s3 的底层数组的内存地址是:%p,s3 的值是:%d
    ", &s3, s3, s3)
    }
    

     

    4、string

    4.1、strings包

    package main
    
    import (
    	"fmt"
    	"strings"
    )
    
    func main() {
    	// string 包的 replace 函数
    	str1 := "heeelloleeeworld"
    	str1 = strings.Replace(str1, "eee", "www", 1)
    	fmt.Println(str1)
    
    	// 判断字符串是否包含子字符串
    	fmt.Println(strings.Contains(str1, "eee"))
    
    	// 判断字符串中是否包含某个字符
    	fmt.Println(strings.ContainsAny(str1, "d"))
    
    	// 判断字符串是否以某个前缀开头
    	fmt.Println(strings.HasPrefix(str1, "heee"))
    
    	// 判断字符串是否以某个字符串结尾
    	fmt.Println(strings.HasSuffix(str1, "rld"))
    
    	// 以指定字符串切分字符串
    	fmt.Println(strings.Split(str1, "eee"))
    }
    

    4.2、strconv包

    package main
    
    import (
    	"fmt"
    	"strconv"
    )
    
    func main() {
    	str1 := "true"
    	b1, _ := strconv.ParseBool(str1)
    	fmt.Printf("%T
    ", b1)
    
    	// Atoi 把 string 转换成 int
    	str2 := "2020"
    	n1,_ := strconv.Atoi(str2)
    	fmt.Printf("%T
    ", n1)
    
    	//
    	n2 := strconv.Itoa(n1)
    	fmt.Printf("%T
    ", n2)
    
    }
    

      

    5、函数

    5.1、函数的声明

    格式:

    parameters1和parameters2都是函数形式参数,value1和value2是返回值,

    func funName(parameters1 type1, parameters2 type2) (value1 type3, value2 type4) {
    	//函数体
    	value1 := 4
    	value2 := 9
    	return
    } 

    5.2、函数的可变参数

    格式:

    args ...type这里表示的可变参

    func funcName([para type], args ...type) {
    	函数体
    }
    

    EXAMPLE:

    func Sum(args ...int) { // 求和
    	sum := 0
    	for i := 0; i < len(args); i++ {
    		sum += args[i]
    	}
    	fmt.Println(sum)
    }
    

    5.3、函数的数据类型

    我们试着打印下函数的数据类型看看

    package main
    
    import "fmt"
    
    func main() {
    	//注意不带括号,带括号的函数表调用执行
    	fmt.Printf("fun11 函数的数据类型是:%T
    ", fun11)	// func()
    	fmt.Printf("fun22 函数的数据类型是:%T
    ", fun22)	// func(int, int, string)
    	fmt.Printf("fun33 函数的数据类型是:%T
    ", fun33)	// func([]int) (int, int)
    
    	// 把函数赋值给一个变量
    	fun44 := fun11
    	fun44()
    	// 指向同一块内存地址
    	fmt.Printf("fun11 函数的内存地址:%p
    ", fun11)
    	fmt.Printf("fun44 函数的内存地址:%p
    ", fun44)
    }
    
    func fun11() {
    	fmt.Println("this is the test!")
    }
    
    func fun22(n1,n2 int, s1 string) {
    
    }
    
    func fun33(s1 []int) (int, int) {
    	return 0,0
    }
    

    5.4、函数的本质

    函数定义时,内存中会开辟一段内存空间给函数用,函数名则指向这段内存空间的地址。

    函数名不带括号,就表示这段内存地址;函数名带括号,就表示执行这个函数。

    5.5、回调

    回调是指,把一个函数当参数,传递给另外一个函数。

    package main
    
    /*
    回调:把一个函数当做参数,传递给另外一个函数
    */
    
    import "fmt"
    
    func main() {
    	res := opt(1, 2, add)
    	fmt.Println(res)
    }
    
    // 加
    func add(a, b int) int {
    	return a + b
    }
    
    //减
    func sub(a, b int) int {
    	return a - b
    }
    
    // 算术运算
    //	           形参名+函数类型
    func opt(a, b int, fun func(int, int) int) int {
    	return fun(a, b)
    }
    

    5.6、闭包

    闭包函数:声明在一个函数中的函数
    闭包:闭包函数总能访问外部函数的变量,外部函数的变量不会因调用而销毁

    package main
    
    import "fmt"
    
    func main() {
    	zhaoyun := walk("赵云")
    	zhangfei := walk("张飞")
    	zhaoyun(2)
    	zhangfei(3)
    	zhangfei(1)
    	zhaoyun(2)
    }
    
    func walk(name string) func(int) {
    	total := 0
    	haha := func(hour int) {
    		total += hour
    		fmt.Printf("%s: 行军%d小时!
    ", name, hour)
    		fmt.Printf("%s: 一共行军%d小时!
    ", name, total)
    	}
    	return haha
    }
    

      

     6、指针

    一个指针变量指向了一个值的内存地址。

    *表示去指针数据

    &表示取地址

    定义:

    // 定义一个存储整数类型的指针
    var p1 *int
    // 定义一个双重指针
    var p2 **int

    使用:

    // 给指针赋值
    p1 = &a
    p2 = &p1
    // 取出指针变量的值
    *p1
    *p2

      

    空指针:

    空指针用nil表示

    7、结构体

    Go 语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型。

    结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。

    定义:

    type struct_variable_type struct {
       member definition
       member definition
       ...
       member definition
    }
    

      

    example:

    package main
    
    import "fmt"
    
    type Books struct {
       title string
       author string
       subject string
       book_id int
    }
    
    
    func main() {
    
        // 创建一个新的结构体
        fmt.Println(Books{"Go 语言", "www.runoob.com", "Go 语言教程", 6495407})
    
        // 也可以使用 key => value 格式
        fmt.Println(Books{title: "Go 语言", author: "www.runoob.com", subject: "Go 语言教程", book_id: 6495407})
    
        // 忽略的字段为 0 或 空
       fmt.Println(Books{title: "Go 语言", author: "www.runoob.com"})
    }
    

      

    访问结构体成员:

    如果要访问结构体成员,需要使用点号 . 操作符

    结构体.成员名
    

      

  • 相关阅读:
    css水平垂直居中
    JavaScript提供了哪几种“异步模式”?
    sort()
    后端开发中,可以在Cache-Control设置的常用指令
    纯函数
    react和vue
    npm(classnames) 更灵活使用类名
    shell知多少?
    常见的HTTP状态码
    axios
  • 原文地址:https://www.cnblogs.com/wufj/p/13417857.html
Copyright © 2011-2022 走看看