GO开发[二]:golang语言基础

gregoryli · · 684 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

[TOC]

一.变量

1.声明变量

变量相当于是对一块数据存储空间的命名,程序可以通过定义一个变量来申请一块数据存储空间,之后可以通过引用变量名来使用这块存储空间。

Go语言引入了关键字var,而类型信息放在变量名之后,变量声明语句不需要使用分号作为结束符,示例如下:
var v1 int
var v2 string
var v3 [10]int // 数组
var v4 []int // 数组切片
var v5 struct {
f int
}
var v6 *int // 指针
var v7 map[string]int // map, key为string类型, value为int类型
var v8 func(a int) int

var关键字的另一种用法是可以将若干个需要声明的变量放置在一起,免得程序员需要重复
写var关键字,如下所示:

var (
v1 int
v2 string
)

对于声明变量时需要进行初始化的场景, var关键字可以保留,但不再是必要的元素:

var v1 int = 10 // 正确的使用方式1
var v2 = 10 // 正确的使用方式2,编译器可以自动推导出v2的类型
v3 := 10 // 正确的使用方式3,编译器可以自动推导出v3的类型

冒号和等号的组合:=,用于明确表达同时进行变量声明和初始化的工作。

不能重复声明:

var i int
i := 2
会导致类似如下的编译错误:
no new variables on left side of :=

2.匿名变量

_是特殊标识符,用来忽略结果

package main

import(
    "fmt"
)

func cal(a int, b int)(int,int) {
    sum := a + b
    avg := (a+b)/2
    return sum, avg
}

func main() {
    _,avg := cal(100,200)
    fmt.Println(avg)
}

二、常量

在Go语言中,常量是指编译期间就已知且不可改变的值。常量可以是数值类型(包括整型、浮点型和复数类型)、布尔类型、字符串类型等。

const Pi float64 = 3.14159265358979323846
const zero = 0.0 // 无类型浮点常量
const (
    size int64 = 1024
    eof = -1 // 无类型整型常量
)
const u, v float32 = 0, 3 // u = 0.0, v = 3.0,常量的多重赋值
const a, b, c = 3, 4, "foo"
// a = 3, b = 4, c = "foo", 无类型整型和字符串常量

定义两个常量a=1和b=2,获取当前时间的秒数,如果能被b整除,则在终端打印b,否则打印a。

package main

import(
    "fmt"
    "time"
)

const (
    a = 1
    b = 2
)

func main() {
    for {
        second := time.Now().Unix()
        fmt.Print(second," ")
        if (second % b == 0) {
            fmt.Println("b")
        } else {
            fmt.Println("a")
        }
        time.Sleep(1000 * time.Millisecond)
    }
}

三、数据类型

1.整型

类 型 长度(字节) 值 范 围
int8 1 -128 ~ 127
uint8(即byte) 1 0 ~ 255
int16 2 -32768 ~ 32767
uint16 2 0 ~ 65535
int32 4 -2147483648 ~ 2147483647
uint32 4 0 ~ 4294967295
int64 8 -9223372036854775808 ~ 9223372036854775807
uint64 8 0 ~ 18446744073709551615
int 平台相关 平台相关
uint 平台相关 平台相关
uintptr 同指针 在32位平台下为4字节, 64位平台下为8字节

对于常规的开发来说,用int和uint就可以了,没必要用int8之类明确指定长度的类型,以免导致移植困难。

var value2 int32
value1 := 64 // value1将会被自动推导为int类型
value2 = value1 // 编译错误
编译错误类似于:
cannot use value1 (type int) as type int32 in assignment。
使用强制类型转换可以解决这个编译错误:
value2 = int32(value1) // 编译通过

eg:

package main

import "fmt"

func main()  {
    var n int16 = 16
    var m int32
    //m=n
    m= int32(n)
    fmt.Printf("32 bit int:%d\n",m)
    fmt.Printf("16 bit int:%d\n",n)
}

2.bool

var v1 bool
v1 = true
v2 := (1 == 2) // v2也会被推导为bool类型

var b bool
b = (1!=0) // 编译正确
fmt.Println("Result:", b) // 打印结果为Result: true

3.数值运算

Go语言支持下面的常规整数运算: +、 -、 *、 /和%。 % 和在C语言中一样是求余运算,比如:
5 % 3 // 结果为: 2

4.浮点型

Go语言定义了两个类型float32和float64,其中float32等价于C语言的float类型,float64等价于C语言的double类型。

var f1 float32
f1 = 12
f2 := 12.0 // 如果不加小数点, f2会被推导为整型而不是浮点型
f1 = float32(f2)//强制类型转换

因为浮点数不是一种精确的表达方式,所以像整型那样直接用==来判断两个浮点数是否相等是不可行的,这可能会导致不稳定的结果。
下面是一种推荐的替代方案:

import "math"
// p为用户自定义的比较精度,比如0.00001
func IsEqual(f1, f2, p float64) bool {
    return math.Fdim(f1, f2) < p
}

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

package main

import (
   "fmt"
   "math/rand"
   "time"
)

func init() {
   rand.Seed(time.Now().UnixNano())
}

func main() {
   for i := 0; i < 10; i++ {
      a := rand.Int()
      fmt.Println(a)
   }

   for i := 0; i < 10; i++ {
      a := rand.Intn(100)
      fmt.Println(a)
   }

   for i := 0; i < 10; i++ {
      a := rand.Float32()
      fmt.Println(a)
   }
}

5.字符

在Go语言中支持两个字符类型,一个是byte(实际上是uint8的别名),代表UTF-8字符串,的单个字节的值;另一个是rune,代表单个Unicode字符。 出于简化语言的考虑, Go语言的多数API都假设字符串为UTF-8编码。尽管Unicode字符在标准库中有支持,但实际上较少使用。

byte.go

package main

import "fmt"

func main() {
   var b byte
   for b =0;b<177;b++{
      fmt.Printf("%d %c\n",b,b)
   }
}

rune.go

package main

import "fmt"

func main() {
    // byte => uint8
    // rune => int32
    s := "golang你好"
    fmt.Println(len(s))
    cnt := 0
    for _, r := range s {
        cnt += 1
        fmt.Printf("%c\n", r)
    }
    fmt.Println("cnt", cnt)
    ss := []rune("hello")
    fmt.Println(ss)
}

6.字符串类型

package main

import "fmt"

func main()  {
    str := "Hello,世界"
    n := len(str)
    fmt.Println(n)
    for i := 0; i < n; i++ {
        ch := str[i] // 依据下标取字符串中的字符,类型为byte
        fmt.Println(i, ch)
    }
    fmt.Println("///////////////////////////")
    str1 := "Hello,世界"
    for i, ch := range str1 {
        fmt.Println(i, ch)//ch的类型为rune
    }
}
/*
12
0 72
1 101
2 108
3 108
4 111
5 44
6 228
7 184
8 150
9 231
10 149
11 140
///////////////////////////
0 72
1 101
2 108
3 108
4 111
5 44
6 19990
9 30028
*/

以字节数组的方式遍历 :这个字符串长度为12。尽管从直观上来说,这个字符串应该只有10个字符。这是因为每个中文字符在UTF-8中占3个字节,而不是1个字节。

以Unicode字符遍历: 以Unicode字符方式遍历时,每个字符的类型是rune(早期的Go语言用int类型表示Unicode字符),而不是byte。

四、值类型和引用类型

值类型:基本数据类型int、float、bool、string以及数组和struct。

引用类型:指针、slice、map、chan等都是引用类型。

值语义和引用语义的差别在于赋值,比如下面的例子:
b = a
b.Modify()
如果b的修改不会影响a的值,那么此类型属于值类型。如果会影响a的值,那么此类型是引用类型。
Go语言中的大多数类型都基于值语义,包括:
基本类型,如byte、 int、 bool、 float32、 float64和string等;
复合类型,如数组(array)、结构体(struct)和指针(pointer)等。

package main

import "fmt"

func main(){
   var a = [3]int{1, 2, 3}
   var b = a
   b[1]++
   fmt.Println(a)// [1 2 3]
   fmt.Println(b)//[1 3 3]
}

b=a赋值语句是数组内容的完整复制。要想表达引用,需要用指针

package main

import "fmt"

func main(){
   var a = [3]int{1, 2, 3}
   var b = a
   var c = &a
   b[1]++
   c[1]++
   fmt.Println(a)
   fmt.Println(b)
   fmt.Println(*c)
   /*
      [1 3 3]
      [1 3 3]
      [1 3 3]
   */
}

c=&a赋值语句是数组内容的引用。变量c的类型不是[3]int,而是*[3]int类型

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

package main

import (
   "fmt"
)

func modify(a int) {
   a = 50
   return
}

func modify1(a *int) {
   *a = 500
}

func main() {
   a := 5
   b := make(chan int, 1)

   fmt.Println("a=", a)
   fmt.Println("b=", b)

   modify(a)
   fmt.Println("a=", a)
   modify1(&a)
   fmt.Println("a=", a)
}

练习:写一个程序,交换两个整数的值。

package main

import "fmt"

func swap(a int, b int) {
   tmp := a
   a = b
   b = tmp
   return
}

func main() {
   one := 1
   two := 2
   swap(one,two)
   fmt.Println("one=",one)
   fmt.Println("two=",two)
}

傻眼了,不变!加星号!

package main

import "fmt"

func swap(a *int, b *int) {
    tmp := *a
    *a = *b
    *b = tmp
    return
}

func swap2(a int,b int) (int,int){
    return b,a
}

func main() {
    one := 1
    two := 2
    swap(&one,&two)
    //one,two=swap2(one,two)
    //one,two=two,one
    fmt.Println(one,two)
}

五、变量的作用域

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

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

package main

import "fmt"

var a = "Greg"

func aa()  {
    fmt.Println(a)
}

func ab()  {
    a = "ningxin"
    fmt.Println(a)
}

func ac() {
    a := 2
    fmt.Println(a)
}

func main() {
    aa()
    ac()
    aa()
    ab()
    aa()
}

a := 2不可能是全局变量,因为这不是声明,而是执行代码,代码块要在函数里,go程序从上到下代码块外的部分只能是声明。

var a int 
a=2

输出什么?

package main

import "fmt"

var a string

func f1() {
   a := "ningxin"
   fmt.Println(a)
   f2()
}

func f2() {
   fmt.Println(a)
}

func main() {
   a = "greg"
   fmt.Println(a)
   f1()
}

有疑问加站长微信联系(非本文作者)

本文来自:博客园

感谢作者:gregoryli

查看原文:GO开发[二]:golang语言基础

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

684 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传