zoukankan      html  css  js  c++  java
  • 第四章 基本结构和基本数据类型

    4.1 文件名、关键字和标识符

    • 以“.go”为后缀。
    • 由小写字母组成,如果以多个部分组成则使用下划线“_”隔开。
    • 以下标识符无效:

        1、lab(以数字开头)

        2、case(go语言关键字)

        3、a+b(包含运算符)

    4.2 go语言的结构和基本要素

    4.2.1 包的概念

    每个go文件只属于一个包。

    一个包可以由多个以“.go”为后缀的源文件组成。

    必须在源文件中非注释的第一行指明这个文件属于哪个包,如:package main

    4.2.2 包导入

    使用import关键字

    import "fmt"

    多个包的导入 :

    import "fmt"
    import "os"

    import "fmt"; import "os"

    import (
        "fmt"
        "os"
    )

    import ("fmt"; "os")

    推荐使用 

    import (
        "fmt"
        "os"
    )

    包的文件路径

    • 包如果不以“./”或“/”开头,则go会在全局文件中查找,例如:fmt
    • 以“./”开头则会在相对目录中查找
    • 以“/”开头的会在绝对目录中查找  

    包的规范和规则

    • 除了“_”符号,包中所有代码对象标识符必须唯一
    • 标识符(包括常量、类型、函数、结构字段等等)以大写开头 ,就可以被外部包的代码所使用。(类似java中的public)
    • 标识符以小写开头,则对外包不可见。(类似java的private)
    • 对外可见的标识符(大写开头),要以包名去访问。
    • 导入一个包如果没有使用,则会引发错误:imported and not used:

    别名的使用

    import fm "fmt"
    // fm将作为fmt 的别名

    4.2.3 函数

    如果你学过java或者php,你可能搞不太清楚函数和方法的区别,但你如果学过python,你会发现go中函数和方法的区别很像,但又不一样。接下来先学习函数吧!

    函数最简单格式:

    func functionName(){}

    规范格式:被外部调用的函数遵循Pascal命名法,即首字母大写。否则遵循驼峰命名法,即第一个字母小写,其余单词首字母大写。

    func functionName(parameter_list)(return_value_ist){
           .........  
    }

    例如:

    func funcName(input1 type1, input2 type2) (output1 type1, output2 type2) {
        // 这里是处理逻辑代码
        // 返回多个值
        return value1, value2
    }

    入口函数 

    main包下面的main函数,作为程序入口,该函数没有参数,也没有返回值。

    4.2.4 注释

    单行注释://

    多行注释:/**/

    几乎所有全局作用域的类型、常量、变量、函数和被导出的对象都应该有一个合理的注释。

    关于注释的规范感兴趣的道友可以自行查取相关知识:godoc工具的使用,在第三章。

    4.2.5 类型

    类型可以是基本类型,如:int、float、bool、string;结构化的(复合的),如:struct、array、slice、 map、channel;只描述类型的行为的,如:interface。

    4.2.6 程序的一般结构

    1. 首先要做的就是命名包
    2. 接着就导包,不用等到包就不需要导入
    3. 接下来就是申明函数、常量、变量等等。

    需要注意的是一个程序只有一个main包并且只有一个main函数作为入口,一个文件中可以包含多个init函数,并且会依次经行初始化工作。

    4.2.7 类型转换

    go语言为了避免像C、C++、java等等语言那样,由于隐式转换可能带来数据的不确定性,因此所有的转换都必须显示说明。

    类似转换可以看作是函数,当然我们也可以自定义自己的类型转换。

    格式:

    valueOfTypeB    =    typeB(valueOfTypeA)

    示例:

    a := 5.0
    b := int(a)

     4.2.8 命名规范

    干净、可读的代码和简洁性是 Go 追求的主要目标。通过 gofmt 来强制实现统一的代码风格。Go 语言中对象的命 名也应该是简洁且有意义的。像 Java 和 Python 中那样使用混合着大小写和下划线的冗长的名称会严重降低代码 的可读性。名称不需要指出自己所属的包,因为在调用的时候会使用包名作为限定符。返回某个对象的函数或方法的 名称一般都是使用名词,没有 Get... 之类的字符,如果是用于修改某个对象,则使用 SetName 。有必须要的话 可以使用大小写混合的方式,如 MixedCaps 或 mixedCaps,而不是使用下划线来分割多个名称。

    4.3 常量

    常量就是运行过程中值和地址不变的量。站在权限角度来看,这个常量是只读类型。

    格式:

    const identifier [type]    = value

    go为了简化操作定义常量的方式主要有两种:

    显式类型定义: 

    const b string = "abc"

    隐式类型定义:

     const b = "abc"

     注意:常量是在编译是就确定的量。

    正确的:

    const b = 1/2;

    错误的:

    const a = functionName() // 不能用函数的返回值作为常量值,因为返回值的地址是不确定的。

    常量几种申明方式:

    单个声明

    const a = 1

    多个申明:值得注意的是,类型必须一致

    1、一般申明

    const (
        b = 1
        a = 2      
    )
    const (
        a = 1
        b
        c = 3
        d = iota
    )

    示例

    package main
    
    import "fmt"
    const (
        a = 1
        b
        c = 3
        d = iota
        e
        f
    )
    func main() {
        fmt.Println("a=", a)
        fmt.Println("b=", b)
        fmt.Println("c=", c)
        fmt.Println("d=", d)
        fmt.Println("e=", e)
        fmt.Println("f=", f)
    }

    结果:

    a= 1
    b= 1
    c= 3
    d= 3
    e= 4
    f= 5

    4.4 变量

    申明格式:var identifier type

    申明用类型多个变量

    var a, b *int;

     多个变量声明

    var a int
    var b bool
    var c string

    简化var

    var (
           a int
           b bool
           c string    
    )
    d := 1 // := 函数局部变量中使用
    a, b, c := 1, "a", false
    
    

    4.4.1 值类型和引用类型

    基本类型(int、float、string、bbool)属于值类型,使用这些类型的时候会直接指向内存中的值。

    引用类型(指针),指向的是一块内存地址。

    本质上来说,值类型和引用类型都是直接指向内存中的值,不同在于值类型指向的是值,而引用类型指向的是值的引用。

    比如:a := "string", 使用&a会得到a的地址,这个地址的值就称为a的引用,而应用类型的变量就是保存这些地址的值。

     下面用一个例子说明一下

    package main
    
    import "fmt"
    
    func main() {
        a := "string"
        b := &a
        fmt.Println("a的值等于:", a)
        fmt.Println("a的地址等于:", &a)
        fmt.Println("b的值等于:", b)
        fmt.Println("b指向的值等于:", *b)
        fmt.Println("b的地址等于:", &b)
        fmt.Println("分割线----------")
        // 同步改变变量的值
        a = "new String"
        fmt.Println("a的值等于:", a)
        fmt.Println("a的地址等于:", &a)
        fmt.Println("b的值等于:", b)
        fmt.Println("b指向的值等于:", *b)
        fmt.Println("b的地址等于:", &b)
        fmt.Println("分割线----------")
        // 引用类型可以修改引用的地址值
        c := "ttt"
        b = &c
        fmt.Println("c的值等于:", c)
        fmt.Println("c的地址等于:", &c)
        fmt.Println("b的值等于:", b)
        fmt.Println("b指向的值等于:", *b)
        fmt.Println("b的地址等于:", &b)
    }

    结果:

    a的值等于: string
    a的地址等于: 0xc00003a1f0
    b的值等于: 0xc00003a1f0
    b指向的值等于: string
    b的地址等于: 0xc000006028
    分割线----------
    a的值等于: new String
    a的地址等于: 0xc00003a1f0
    b的值等于: 0xc00003a1f0
    b指向的值等于: new String
    b的地址等于: 0xc000006028
    分割线----------
    c的值等于: ttt
    c的地址等于: 0xc00003a240
    b的值等于: 0xc00003a240
    b指向的值等于: ttt
    b的地址等于: 0xc000006028

     可能使用过java的人看到a重新赋值后地址依然没有感到疑惑,解释一下,在java中string类型是引用类型(类似例子中的b)。

     在这个例子中我们同样看到,使用“&”能够获得该变量的地址,即为引用,使用“*”能从引用中获取到指向的值。

     4.4.2 init函数

    变量除了可以在全局声明中初始化,也可以在 init 函数中初始化。这是一类非常特殊的函数,它不能够被人为调 用,而是在每个包完成初始化后自动执行,并且执行优先级比 main 函数高。

    每一个源文件都可以包含一个或多个 init 函数。初始化总是以单线程执行,并且按照包的依赖关系顺序执行。

    示例:

    package main
    
    var PI float64
    func main() {
    
    }
    
    func init(){
        PI = 122333.5666
    }
    func init()  {
        print("PI", PI, "
    ")
    }
    func init()  {
        PI = 11111.11111
    }
    func init()  {
        print("PI=", PI, "
    ")
    }

    4.5 基本类型和运算

    bool类型

    bool类型的取值只有两个:true和false;可以通过运算符比较获得。

    整型(整数)

    • int8(-128 -> 127)
    • int16(-32768 -> 32767)
    • int32(-2,147,483,648 -> 2,147,483,647)
    • int64(-9,223,372,036,854,775,808 -> 9,223,372,036,854,775,807)

    无符号整数:

    • uint8(0 -> 255)
    • uint16(0 -> 65,535)
    • uint32(0 -> 4,294,967,295)
    • uint64(0 -> 18,446,744,073,709,551,615

    int和uint在32位操作系统上4个字节,64位系统8个字节

    float类型(小数)

    • float32(+- 1e-45 -> +- 3.4 * 1e38)
    • float64(+- 5 1e-324 -> 107 1e308)

    复数

    字符类型

    var ch byte = 'A'

    • 判断是否为字母: unicode.IsLetter(ch)
    • 判断是否为数字: unicode.IsDigit(ch)
    • 判断是否为空白符号: unicode.IsSpace(ch)

    字符串

    单引号和双引号的区别:单引号只能写一个字符或者是ASCII码,双引号是字符串,这个定义跟C语言一样,和c/c++不一样的是Go字符串根据长度限定,不是特殊字符“”。一般作为C语言字符数组的结束符。

    说起字符串还得要说一下转义字符,这些常用于字符串中,主要转义字符如下:

    • :换行符
    • :回车符
    • :tab 键
    • u 或 U :Unicode 字符
    • \ :反斜杠自身

    两个字符串连接使用"+"

    运算符优先级

    有些运算符拥有较高的优先级,二元运算符的运算方向均是从左至右。下表列出了所有运算符以及它们的优先级,由 上至下代表优先级由高到低:

    优先级 运算符
    7 ^(按位取反)、!(非)
    6 *(乘)、/(除)、%(求余)、<<(位运算左移)、>>(位运算右移)、&(按位与)
    5 +(加)、-(减)、|(按位或)、^(按位异或)
    4 ==(相等)、!=(不等)、>(大于)、>= (大于等于)、<(小于)、<=(小于等于)
    3 <- (管道传值)
    2 &&(与)
    1 ||(或)

    大家可以自行查询关于运算符
    类型别名

    type TZ int

    package main
    type TZ int
    func main() {
        var a, b TZ = 3, 4
        c := a + b
        print(c)
    }

    4.6 strings包

    判断前缀:strings.HasPerfix(s, prefix string) bool

    判断是否以“s”开头

    package main
    
    import (
        "fmt"
        "strings"
    )
    
    func main() {
        s := "string"
        fmt.Println(strings.HasPrefix(s, "s"))  // true
        fmt.Println(strings.HasPrefix(s, "t"))  // false
    }

    判断后缀:strings.HasSuffix(s, suffix string) bool

    package main
    
    import (
        "fmt"
        "strings"
    )
    
    func main() {
        s := "string"
        fmt.Println(strings.HasSuffix(s, "g"))  // true
        fmt.Println(strings.HasSuffix(s, "t"))  // false
    }

    包含子字符串: strings.Contains(s, substr string) bool

    package main
    
    import (
        "fmt"
        "strings"
    )
    
    func main() {
        s := "string"
        fmt.Println(strings.Contains(s, "ri"))  // true
        fmt.Println(strings.Contains(s, "2e"))  // false
    }

    判断子字符串的索引位置,找不到返回-1:strings.index(s, substr string) int

    package main
    
    import (
        "fmt"
        "strings"
    )
    
    func main() {
        s := "my name is hardy,last name is kay"
        fmt.Println(strings.Index(s, "hardy")) // 11
        fmt.Println(strings.Index(s, "is"))  // 8
        fmt.Println(strings.Index(s, "hello"))  // -1
    }

    字符串替换: strings.Replace(str, old, new string, n int)  string

    package main
    
    import (
        "fmt"
        "strings"
    )
    
    func main() {
        s := "my name is hardy,last name is kay"
        fmt.Println(strings.Replace(s, "hardy", "hello", 2)) // my name is hello,last name is kay
        fmt.Println(strings.Replace(s, "is", "hello", 2)) // my name hello hardy,last name hello kay
    }

    统计子字符串出现的次数: strings.Count(s, substr string) int

    package main
    
    import (
        "fmt"
        "strings"
    )
    
    func main() {
        s := "my name is hardy,last name is kay"
        fmt.Println(strings.Count(s, "hardy")) // 1
        fmt.Println(strings.Count(s, "hello")) // 0
        fmt.Println(strings.Count(s, "is")) // 2
        fmt.Println(strings.Count(s, "s")) // 3
    }

    重复字符串: strings.Repeat(s, 10) string

    package main
    
    import (
        "fmt"
        "strings"
    )
    
    func main() {
        s := "hardy"
        fmt.Println(strings.Repeat(s, 10)) // hardyhardyhardyhardyhardyhardyhardyhardyhardyhardy
    }

    全部转为大写:ToUpper(s string) string

    package main
    
    import (
        "fmt"
        "strings"
    )
    
    func main() {
        s := "my name is hardy,last name is kay"
        fmt.Println(strings.ToUpper(s)) // MY NAME IS HARDY,LAST NAME IS KAY
    }

    全部转为小写:ToLower(s string) string

    package main
    
    import (
        "fmt"
        "strings"
    )
    
    func main() {
        s := "MY NAME IS HARDY,LAST NAME IS KAY"
        fmt.Println(strings.ToLower(s)) // my name is hardy,last name is kay
    }

    剔除开头或结尾的字符:Trim(s string, cutset string) string

    类似的操作函数还有:TrimSpace 来剔除字符串开头和结尾的空白符号,剔除开头或者结尾的字符串,则可以使用 TrimLeft 或者 TrimRight 来实现。

    package main
    
    import (
        "fmt"
        "strings"
    )
    
    func main() {
        s := "my name is hardy, my last name is kay my"
        fmt.Println(strings.Trim(s, "my")) //  name is hardy, my last name is kay
    }

     分割字符串

    空白字符分割:Fields(s string) []string

    package main
    
    import (
        "fmt"
        "strings"
    )
    
    func main() {
        s := "my name is hardy              last name is kay my"
        r := strings.Fields(s)
        for k,v := range r{
            fmt.Println("k=", k, ", v=", v)
        }
    }

    结果:

    k= 0 , v= my
    k= 1 , v= name
    k= 2 , v= is
    k= 3 , v= hardy
    k= 4 , v= last
    k= 5 , v= name
    k= 6 , v= is
    k= 7 , v= kay
    k= 8 , v= my

     指定字符串分割:Split(s, sep string) []string

    package main
    
    import (
        "fmt"
        "strings"
    )
    
    func main() {
        s := "my name is hardy last name is kay my"
        r := strings.Split(s, "i")
        for k,v := range r{
            fmt.Println("k=", k, ", v=", v)
        }
    }

     结果:

    k= 0 , v= my name
    k= 1 , v= s hardy last name
    k= 2 , v= s kay my

     拼接slice到字符串

    package main
    
    import (
        "fmt"
        "strings"
    )
    
    func main() {
        s := "my name is hardy last name is kay my"
        r := strings.Fields(s)
        fmt.Println(strings.Join(r, ",")) //my,name,is,hardy,last,name,is,kay,my 
    }
  • 相关阅读:
    [PHP] 小数转科学计数法, 小数保留 n 位
    [Blockchain] Cosmos Starport 101
    [Blockchain] Cosmos Starport 地址前缀的变更方式
    [Blockchain] Cosmos Starport 安装的三种方式
    [ML] 机器学习的 7 步走
    [FAQ] MEMORY ALLOC FAILED: mmap with HUGETLB failed, attempting without it (you should fix your kernel)
    [FAQ] FastAdmin epay 微信公众号支付 JSAPI 支付必须传 openid ?
    [TP5] 动态绑定指定默认模块, 解决: 控制器不存在:appindexcontrollerApi
    [TP5] ThinkPHP 默认模块和单模块的设置方式
    [TP5] 浅谈 ThinkPHP 的 Hook 行为事件及监听执行
  • 原文地址:https://www.cnblogs.com/hardykay/p/12901820.html
Copyright © 2011-2022 走看看