• Go语言学习之2 包、函数、常量、数据类型、字符操作


    第一部分:基本数据类型和操作符

    1. 文件名&关键字&标识符

        (1)所有go源码以.go结尾
        (2)标识符以字母或下划线开头,大小写敏感,比如:

             a. boy     b. Boy     c. a+b     d. 0boy     e. _boy     f. =_boy     g. _

             其中:a  b  e符合表示符的命名规范

        (3) _是特殊标识符,用来忽略结果
        (4)保留关键字

    2. Go程序基本结构

    package main
    
    import (
        "fmt"
    )
    
    func main() {
         fmt.Println("hello world!")
    }

    (1) 任何一个代码文件隶属于一个包

    (2)import 关键字,引用其他包:
             import("fmt")
             import("os")
            通常习惯写成:
            import (
                "fmt"
                "os"
            )

    (3) golang可执行程序,package main,
             并且有且只有一个main入口函数
    (4)包中函数调用:
             a. 同一个包中函数,直接调用
             b. 不同包中函数,通过包名+点+函数名进行调用
    (5)包访问控制规则:
            a. 大写意味着这个函数/变量是可导出的
            b. 小写意味着这个函数/变量是私有的,包外部不能访问

    准备:先创建F:Goprojectsrcgo_devday2目录,并在该目录下创建example1,example2目录,并在example2目录下创建add,main,test目录

    练习1. 写一个程序,对于给定一个数字n,求出所有两两相加等于n的组合。比如: 对于n=5,所有组合如下所示:

            0 + 5 = 5
            1 + 4 = 5
            2 + 3 = 5
            3 + 2 = 5
            4 + 1 = 5
            5 + 0 = 5

    在F:Goprojectsrcgo_devday2example1目录下创建main.go文件

     1 package main 
     2 
     3 import "fmt"
     4 
     5 func list(n int) {
     6     for i := 0; i <= n; i++ {
     7         fmt.Printf("%d + %d = %d
    ", i, n - i, n)
     8     }
     9 }
    10 
    11 func main() {
    12     list(10)
    13 }
    练习1

    练习2:一个程序包含两个包add和main,其中add包中有两个变量:Name和age。请问main包中如何访问Name和age?

    先来看下面例子1:

     1 package main 
     2 
     3 import "fmt"
     4 
     5 func test() {
     6     fmt.Println(str)
     7 }
     8 
     9 func main() {
    10     test()
    11 }
    12 
    13 var str string = "hello world"
    View Code

    运行结果:

    注意: 我们定义了一个全局变量 str 为字符串类型,可以看出在程序运行时,全局变量是先被初始化, 且不像C语言,全局变量初始化与其位置无关。

    例子2:

    在add目录下创建add.go文件,内容如下

    1 package add
    2 
    3 var Name string = "hello world"
    4 var age int = 10
    View Code

    在main目录下创建main.go文件,内容如下

     1 package main 
     2 
     3 import (
     4     "fmt"
     5     "go_dev/day2/example2/add"
     6 )
     7 
     8 func main() {
     9     fmt.Println("Name = ", add.Name)
    10     fmt.Println("age = ", add.age)
    11 }
    View Code

    运行该程序:

    报错的原因是:在go中变量首字母大写表示该变量可以导出,由于age首字母小写无法导出所以报错,解决方法就是将 age -> Age。

    改完之后运行结果如下:

    练习3: 包别名的应用,开发一个程序,使用包别名来访问包中的函数?

     其中add.go不变,main.go如下: 其中在引入包前面加别名(a "go_dev/day2/example2/add"

     1 package main 
     2 
     3 import (
     4     "fmt"
     5     a "go_dev/day2/example2/add"
     6 )
     7 
     8 func main() {
     9     fmt.Println("Name = ", a.Name)
    10     fmt.Println("age = ", a.Age)
    11 }
    View Code

    运行结果:

    练习4: 每个源文件都可以包含一个init函数,这个init函数自动被go运行框架调用。开发一个程序演示这个功能?

    首先再来看下练习2:

    add.go

    1 package add
    2 
    3 var Name string
    4 var Age int
    5 
    6  Name = "hello world"
    7  Age  = 10
    View Code

    main.go

     1 package main 
     2 
     3 import (
     4     "fmt"
     5     a "go_dev/day2/example2/add"
     6 )
     7 
     8 func main() {
     9     fmt.Println("Name = ", a.Name)
    10     fmt.Println("age = ", a.Age)
    11 }
    View Code

    运行结果:

    结果分析:报错的原因是 Name = "hello world" 和 Age = 10没有放在函数体里面

    修改add.go为:

    1 package add
    2 
    3 var Name string
    4 var Age int
    5 
    6 func Change() {
    7     Name = "hello world"
    8     Age  = 10
    9 }
    View Code

    注意:add.go方法名Change首字母必须大写,否则无法导出被外部调用。

    修改main.go为:

     1 package main 
     2 
     3 import (
     4     "fmt"
     5     a "go_dev/day2/example2/add"
     6 )
     7 
     8 func main() {
     9     a.Change()
    10     fmt.Println("Name = ", a.Name)
    11     fmt.Println("age = ", a.Age)
    12 }
    View Code

    运行结果:

    再来看练习4:

    add.go将Change修改为init,init函数自动被go运行框架调用

    1 package add
    2 
    3 var Name string
    4 var Age int
    5 
    6 func init() {
    7     Name = "hello world"
    8     Age  = 10
    9 }
    add.go

    main.go

     1 package main 
     2 
     3 import (
     4     "fmt"
     5     a "go_dev/day2/example2/add"
     6 )
     7 
     8 func main() {
     9     fmt.Println("Name = ", a.Name)
    10     fmt.Println("age = ", a.Age)
    11 }
    main.go

    运行结果:

    练习5: 包的只初始化,不引用。请开发一个程序,演示这个做法?

     add.go

     1 package add
     2 
     3 import(
     4      _ "go_dev/day2/example2/test"
     5 )
     6 
     7 func init () {
     8     Name = "hello world"
     9     Age = 20
    10     
    11 }
    12 
    13 var Name string = "xxxxx"
    14 var Age int = 100
    add.go

    test.go(在test目录下创建)

     1 package test
     2 
     3 import(
     4     "fmt"
     5 )
     6 
     7 var Name string = "this is in test package"
     8 var Age int = 1000
     9 
    10 func init() {
    11     fmt.Println("this is a test")
    12     fmt.Println("test.package.Name=", Name)
    13     fmt.Println("test.package.age=", Age)
    14 
    15     Age = 10
    16     fmt.Println("test.package.age=", Age)
    17 }
    test.go

    main.go

     1 package main 
     2 
     3 import (
     4     "fmt"
     5     a "go_dev/day2/example2/add"
     6 )
     7 
     8 func main() {
     9     fmt.Println("Name = ", a.Name)
    10     fmt.Println("age = ", a.Age)
    11 }
    main.go

    下运行结果:

    结果分析:

        (1)在add.go中的 _ 表示包的只初始化(只执行test.go中的init函数),不引用。

        (2)变量 Name和Age在每个包里面是相互独立的,在test.go中修改Name和Age并不会影响add.go中的这两个变量

        (3)在add.go中,init函数是在全局变量Name和Age的前面,但是其值依然被改变(执行顺序是先初始化全局变量->init,因此值会被改变)。

    3. 函数声明和注释

    (1)函数声明: func 函数名字 (参数列表) (返回值列表){}

    例如:

    func add() {
    }
    
    func add(a int, b int) int {
    }
    
    func add(a int, b int) int, int {
    }

    (2)注释,两种注释,单行注释: // 和多行注释  /* */

    //add 计算两个整数之和,并返回结果
    func add(a int, b int){
    }
    
    /*add 计算两个整数之和,
    并返回结果*/
    func add(a int, b int){
    }

    4. 常量和变量

    常量:

    (1)常量使用const 修饰,代表永远是只读的,不能修改。
    (2)const 只能修饰boolean,number(int相关类型、浮点类型、complex)和string。
    (3)语法:const identifier [type] = value,其中type可以省略。

    const b string = "hello world"
    const b = "hello world"
    const Pi = 3.1415926
    const a = 9/3
    const c = getValue() //error

    (4)比较优雅的写法:

    const (
        a = 0
        b = 1
        c = 2
    )

    (5)更加专业的写法:

    const (
        a = iota
        b //1
        c //2
    )

    练习6:定义两个常量Man=1和Female=2,获取当前时间的秒数,如果能被Female整除,则在终端打印female,否则打印man。

     1 package main
     2 
     3 import (
     4     "fmt"
     5     "time"
     6 )
     7 
     8 const (
     9     Man = 1
    10     Female = 2
    11 )
    12 
    13 func main() {
    14     for {
    15         cur_time := time.Now().Unix()
    16         if (cur_time % Female == 0) {
    17                 fmt.Println("Female")
    18             } else {
    19                 fmt.Println("Man")
    20             }
    21         //time.Sleep(1000 * time.Millisecond)
    22         time.Sleep(time.Second)
    23     }
    24 }
    练习6

    变量:

    语法:var identifier type

    例1:

    var a int
    var b string
    var c bool
    var d int = 8
    var e string = "hello world"

    例2:

    var (
        a int //默认为0
        b string //默认为""
        c bool //默认为false
        d int = 8
        e string = "hello world"
    )

    例3:

    var (
        a int //默认为0
        b string //默认为""
        c bool //默认为false
        d = 8
        e = "hello world"
    )

    练习7:写一个程序获取当前运行的操作系统名称和PATH环境环境变量的值,并打印在终端。

     1 package main 
     2 
     3 import (
     4    "fmt"
     5    "os"
     6 )
     7 
     8 func main() {
     9     var go_root = os.Getenv("GOROOT");
    10     fmt.Printf("The go root is: %s
    ", go_root)
    11     var path = os.Getenv("PATH")
    12     fmt.Printf("Path is: %s
    ", path)
    13 }
    练习7

    5. 值类型和引用类型

    值类型:变量直接存储值,内存通常在栈中分配。比如:基本数据类型int、float、bool、string以及数组和struct。

    引用类型:变量存储的是一个地址,这个地址存储最终的值。内存通常在堆上分配。通过GC回收。比如:引用类型:指针、slice、map、chan等都是引用类型。

    例8: 写一个程序用来打印值类型和引用类型变量到终端,并观察输出结果。

     1 package main
     2 
     3 import (
     4     "fmt"
     5 )
     6 
     7 func modify(a int) {
     8     a = 10
     9 }
    10 
    11 func modify1(a *int) {
    12     *a = 10
    13 }
    14 
    15 func main() {
    16     a := 5
    17     b := make(chan int, 1)
    18 
    19     fmt.Println("a=", a) //a= 5
    20     fmt.Println("b=", b) //b= 0xc0420320e0
    21 
    22     modify(a)
    23     fmt.Println("a=", a) //a= 5
    24     modify1(&a)
    25     fmt.Println("a=", a) //a= 10
    26 }
    例8

    例9:写一个程序,交换两个整数的值。比如: a=3; b=4; 交换之后:a=4;b=3。

     1 package main
     2 
     3 import "fmt"
     4 
     5 //交换a和b的值(通过指针)
     6 func swap(a *int, b *int) {
     7     tmp := *a
     8     *a = *b
     9     *b = tmp
    10 }
    11 
    12 //交换a和b的值
    13 func swap1(a int, b int) (int, int) {
    14     return b, a
    15 }
    16 
    17 //a和b的值不会发生变化
    18 func swap2(a int, b int) {
    19     tmp := a
    20     a = b
    21     b = tmp
    22 }
    23 
    24 func test() {
    25     var a int8 = 100
    26     // cannot use a (type int8) as type int16 in assignment
    27     //var b int16 = a
    28     var b int16 = int16(a)  //和C语言有所不同
    29     fmt.Printf("a=%d b=%d
    ", a, b)
    30 }
    31 
    32 func main() {
    33     first := 100
    34     second := 200
    35     //swap(&first, &second) //first=200  second=100
    36     //first, second = swap1(first, second) //first=200  second=100
    37     first, second = second, first //first=200  second=100
    38     fmt.Println("first=", first)
    39     fmt.Println("second=", second)
    40 
    41     test()
    42 }
    练习9

    6. 变量的作用域

    (1)在函数内部声明的变量叫做局部变量,生命周期仅限于函数内部。

    (2)在函数外部声明的变量叫做全局变量,生命周期作用于整个包,如果是大写的,则作用于整个程序。

    练习10: 请指出下面程序的输出是什么?

     1 var a = "G"
     2 package main() {
     3     n()
     4     m()
     5     n()
     6 }
     7 
     8 func n() {
     9     fmt.Println(a)
    10 }
    11 
    12 func m() {
    13     a = "0"
    14     fmt.Println(a)
    15 }
    练习10

    练习11:请指出下面程序的输出是什么?

     1 var a = "G"
     2 package main() {
     3     n()
     4     m()
     5     n()
     6 }
     7 
     8 func n() {
     9     fmt.Println(a)
    10 }
    11 
    12 func m() {
    13     a := "0"
    14     fmt.Println(a)
    15 }
    练习11

    练习12:请指出下面程序的输出是什么?

     1 package main 
     2 
     3 var a string
     4 
     5 import "fmt"
     6 
     7 func main() {
     8     a = "G"
     9     fmt.Println(a)
    10     f1()
    11 }
    12 
    13 func f1() {
    14     a := "O"
    15     fmt.Println(a)
    16     f2()
    17 }
    18 
    19 func f2() {
    20     fmt.Println(a)
    21 }
    练习12

    7. 数据类型和操作符

    数据类型:

    (1)bool类型,只能存true和false
    (2)相关操作符, !、&&、||

    (3)数字类型,主要有int、int8、int16、int32、int64、uint8、uint16、uint32、uint64、float32、float64

    (4)类型转换,type(variable),比如:var a int=8;  var b int32=int32(a)

    package main
    
    func main() {
        a int
        b int32
        a = 15
        b = a + a //compiler error
        b = b + 5 //ok: 5 is constant
    }

    (5)字符类型:var a byte 例如:var a byte = 'c'
    (6)字符串类型: var str string 例如: var str string = "hello world"

    字符串表示两种方式: 1)双引号   会识别转义字符

    2)``(反引号) 以字符串的原生形式输出,包括换行和特殊字符,可以实现防止攻击、输出源代码等效果

    例如:

     1 package main
     2 
     3 import "fmt"
     4 
     5 func main() {
     6     var str = "hello world
    "
     7     var str1 = `
     8     床前明月光,
     9     疑是地上霜。
    10     举头望明月,
    11     我是郭德纲。
    12     `
    13     var b byte = 'c'
    14 
    15     fmt.Println(str)
    16     fmt.Println(str1)
    17     fmt.Println(b) //99
    18     fmt.Printf("%c
    ", b)
    19 }
    View Code

    (7)派生类型

    包括:
          (a) 指针类型(Pointer)
          (b) 数组类型
          (c) 结构化类型(struct)
          (d) Channel 类型
          (e) 函数类型
          (f) 切片类型

     1 package main
     2 
     3 import "fmt"
     4 
     5 //字符串反转
     6 func reverse(str string) string {
     7     var result string
     8     strLen := len(str)
     9     for i := 0; i < strLen; i++ {
    10         result = result + fmt.Sprintf("%c", str[strLen-i-1])
    11     }
    12     return result
    13 }
    14 
    15 //字符串反转
    16 func reverse1(str string) string {
    17     var result []byte
    18     tmp := []byte(str)
    19     length := len(str)
    20     for i := 0; i < length; i++ {
    21         result = append(result, tmp[length-i-1])
    22     }
    23     return string(result)
    24 }
    25 
    26 func main() {
    27     var str1 = "hello"
    28     str2 := "world"
    29 
    30     //str3 := str1 + " " + str2
    31     str3 := fmt.Sprintf("%s %s", str1, str2)
    32     n := len(str3)
    33 
    34     fmt.Println(str3)
    35 
    36     fmt.Printf("len(str3)=%d
    ", n)
    37 
    38     substr := str3[0:5]
    39     fmt.Println(substr)
    40 
    41     substr = str3[6:]
    42     fmt.Println(substr)
    43 
    44     result := reverse(str3)
    45     fmt.Println(result)
    46 
    47     result = reverse1(result)
    48     fmt.Println(result)
    49 }
    切片

          (g) 接口类型(interface)
          (h) Map 类型

    格式化输出:

    通用:
    %v    值的默认格式表示。当输出结构体时,扩展标志(%+v)会添加字段名
    %#v   值的Go语法表示
    %T    值的类型的Go语法表示
    %%    百分号
    
    布尔值:
    %t    单词true或false
    
    整数:
    %b    表示为二进制
    %c    该值对应的unicode码值
    %d    表示为十进制
    %o    表示为八进制
    %q    该值对应的单引号括起来的go语法字符字面值,必要时会采用安全的转义表示
    %x    表示为十六进制,使用a-f
    %X    表示为十六进制,使用A-F
    %U    表示为Unicode格式:U+1234,等价于"U+%04X"
    
    浮点数、复数的两个组分:
    %b    无小数部分、二进制指数的科学计数法,如-123456p-78;参见strconv.FormatFloat %e    科学计数法,如-1234.456e+78 %E    科学计数法,如-1234.456E+78 %f  
          有小数部分但无指数部分,如123.456 %F    等价于%f %g    
          根据实际情况采用%e或%f格式(以获得更简洁、准确的输出)
    %G    根据实际情况采用%E或%F格式(以获得更简洁、准确的输出)
    
    字符串和[]byte1 %s  直接输出字符串或者[]byte %q    该值对应的双引号括起来的go语法字符串字面值,必要时会采用安全的转义表示
    2 %x  每个字节用两字符十六进制数表示(使用a-f)
    3 %X  每个字节用两字符十六进制数表示(使用A-F)
    
    指针:
    %p    表示为十六进制,并加上前导的0x
    
    其它flag:
    +    总是输出数值的正负号;对%q(%+q)会生成全部是ASCII字符的输出(通过转义);
    -    在输出右边填充空白而不是默认的左边(即从默认的右对齐切换为左对齐);
    #    切换格式:
        八进制数前加0(%#o),十六进制数前加0x(%#x)或0X(%#X),指针去掉前面的0x(%#p);
        对%q(%#q),如果strconv.CanBackquote返回真会输出反引号括起来的未转义字符串;
        对%U(%#U),如果字符是可打印的,会在输出Unicode格式、空格、单引号括起来的go字面值;
    ' ' 对数值,正数前加空格而负数前加负号;
        对字符串采用%x或%X时(% x或% X)会给各打印的字节之间加空格;
    0   使用0而不是空格填充,对于数值类型会把填充的0放在正负号后面;

    例如:

     1 package main
     2 
     3 import "fmt"
     4 
     5 func main() {
     6     var a int = 100
     7     var b bool
     8     c := 'a'
     9 
    10     fmt.Printf("%+v
    ", a) //100
    11     fmt.Printf("%#v
    ", b) //false
    12     fmt.Printf("%T
    ", c) //int32
    13     fmt.Printf("90%%
    ") //90%
    14     fmt.Printf("%t
    ", b) //false
    15     fmt.Printf("%b
    ", 100) //1100100
    16     fmt.Printf("%f
    ", 199.22) //199.220000
    17     fmt.Printf("%q
    ", "this is a test") //"this is a test"
    18     fmt.Printf("%x
    ", 39839333) //25fe665
    19     fmt.Printf("%p
    ", &a) //0xc04203c1d0
    20 
    21     str := fmt.Sprintf("a=%d", a) //"a=100"
    22     fmt.Printf("%q
    ", str)
    23 }
    格式化输出

    操作符:

    (5)逻辑操作符: == 、!=、<、<=、>和 >=。

    (6)数学操作符:+、-、*、/等等。

    练习13:使用math/rand生成10个随机整数,10个小于100的随机整数以及10个随机浮点数?

     1 package main
     2 
     3 import (
     4     "fmt"
     5     "math/rand"
     6     "time"
     7 )
     8 
     9 func init() {
    10     rand.Seed(time.Now().UnixNano())
    11 }
    12 
    13 func main() {
    14     for i := 0; i < 10; i++ {
    15         a := rand.Int()
    16         fmt.Println(a)
    17     }
    18 
    19     for i := 0; i < 10; i++ {
    20         a := rand.Intn(100)
    21         fmt.Println(a)
    22     }
    23 
    24     for i := 0; i < 10; i++ {
    25         a := rand.Float32()
    26         fmt.Println(a)
    27     }
    28 
    29 }
    练习13

     练习:

    14. 判断 101-200 之间有多少个素数,并输出所有素数。

     1 package main 
     2 
     3 import (
     4     "fmt"
     5     "math"
     6 )
     7 
     8 func isPrime1(num int) bool {
     9     for i := 2; i < num; i++ {
    10         if (num % i == 0) {
    11             return false
    12         }
    13     }
    14     return true
    15 }
    16 
    17 //optimization
    18 func isPrime2(num int) bool {
    19     for i := 2; i <= int(math.Sqrt(float64(num))); i++ {
    20         if (num % i == 0) {
    21             return false
    22         }
    23     }
    24     return true
    25 }
    26 
    27 func main(){
    28     var m int
    29     var n int
    30     var primeNum int
    31     fmt.Println("Please input start and end num >>")
    32     fmt.Scanf("%d%d", &m, &n)
    33 
    34     for i := m; i <= n; i++ {
    35         /*
    36         if (isPrime(i)) {
    37             fmt.Println(i)
    38             primeNum += 1
    39         }*/
    40 
    41         if (isPrime2(i)) {
    42             fmt.Println(i)
    43             primeNum += 1
    44         }
    45     }
    46 
    47     fmt.Println("primeNum = ", primeNum)
    48 }
    练习14

    15. 打印出100-999中所有的“水仙花数”,所谓“水仙花数”是指一个三位数,其各位数字立方和等于该数本身。例如:153 是一个“水仙花数”,因为 153=1 的三次方+5 的三次方+3 的三次方。 

     1 package main 
     2 
     3 import (
     4     "fmt"
     5 )
     6 
     7 func isNarcNumber(num int) bool {
     8     var i, j, k int
     9 
    10     i = num%10
    11     j = num/10%10
    12     k = num/100
    13     sum := i*i*i + j*j*j + k*k*k
    14 
    15     return (sum == num)
    16 }
    17 
    18 func main() {
    19     var m, n int
    20     var totalNum int
    21     fmt.Println("Input a number(100-999) >>")
    22     fmt.Scanf("%d%d", &m, &n)
    23     for i := m; i <= n; i++ {
    24         if (isNarcNumber(i)) {
    25             fmt.Println(i)
    26             totalNum += 1
    27         }
    28     }
    29     
    30     fmt.Println("total narcissus number ", totalNum)
    31 }
    练习15
     1 package main
     2 
     3 import (
     4     "fmt"
     5     "strconv"
     6 )
     7 
     8 func main() {
     9     var str string
    10     fmt.Println("Input a number(100-999) >> ")
    11     fmt.Scanf("%s", &str)
    12 
    13     var result = 0
    14     for i := 0; i < len(str); i++ {
    15         num := int(str[i] - '0')
    16         result += (num * num * num)
    17     }
    18 
    19     number, err := strconv.Atoi(str)
    20     if err != nil {
    21         fmt.Printf("Can not convert %s to int
    ", str)
    22         return
    23     }
    24 
    25     if result == number {
    26         fmt.Printf("%d is narcissus
    ", number)
    27     } else {
    28         fmt.Printf("%d is not narcissus
    ", number)
    29     }
    30 }
    判断一个数是否是水仙花数

    16. 对于一个数n,求n的阶乘之和,即: 1! + 2! + 3!+…n !

     1 package main 
     2 
     3 import (
     4     "fmt"
     5 )
     6 
     7 func computFact(num int) uint64 {
     8     var s uint64 = 1
     9     var sum uint64 = 0
    10     for i := 1; i <= num; i++ {
    11         s *= uint64(i)
    12         fmt.Printf("%d!=%v
    ", i, s)
    13         sum += s
    14     }
    15 
    16     return sum
    17 }
    18 
    19 func main() {
    20     var num int
    21     fmt.Println("Input a number (greater than 1) >> ")
    22     fmt.Scanf("%d", &num)
    23 
    24     s := computFact(num)
    25     fmt.Println(s)
    26 }
    练习16
  • 相关阅读:
    96. Unique Binary Search Trees
    515. Find Largest Value in Each Tree Row
    网络中数据传输的过程
    ARP/RARP协议
    JAVA静态代码块的作用及执行顺序
    MySQL中大于等于小于等于的写法
    Mybatis常见面试题总结及答案
    安全框架Shiro和Spring Security比较
    Excel VBA 连接各种数据库(一) VBA连接MySQL数据库
    Servlet、Servlet容器等内容讲解
  • 原文地址:https://www.cnblogs.com/xuejiale/p/10340091.html
Copyright © 2020-2023  润新知