Go的基础语法——Golang学习笔记2

文章目录

      • 变量、常量和枚举
        • 内建变量类型
        • 变量的定义和初始化
        • 数据类型之复数
        • 类型转化
        • 常量
        • 特殊的常量-枚举
      • 条件与循环语句
        • 条件语句
        • 循环语句
      • 函数
      • 指针

变量、常量和枚举

内建变量类型

内建变量类型有:

  1. bool、string
  2. (u)int、(u)int8、(u)int16、(u)int32、(u)int64、 uintptr(指针)
  3. byte、rune(相当char,但是是32bit即4字节)
  4. float32、 float64、complex64(复数,实部为32bit,虚部为32bit)、complex128(复数,实部为64bit,虚部为64bit)

变量的定义和初始化

  1. 第一种:只定义变量未初始化
  • 在Golang中未初始化的变量(包内部变量和函数内变量)都有默认值,可以只定义就使用。
  • 下列代码中定义变量a,s。输出结果分别为0和空字符串
func variableZeroValue(){
	// 定义变量,初始化,合理的初始值
	// 在C中未初始化的局部变量(自动变量)初始值随机分配,不确定的,而全局变量 、静态变量初始值为0
	// 在java中未初始化的成员变量有默认值,而局部变量没有默认值
	var a int
	var s string

	fmt.Print(a, s)
	fmt.Printf("\n%d %q\n", a, s)
}


Println 打印的每一项之间都会有空格,Print 没有
Println 会自动换行,Print 不会
Printf 是格式化输出,需要占位符

  1. 第二种:变量常规的定义和初始化
  • 通常定义变量的格式是 var 变量名 变量类型 = 变量值
  • Go语言中的函数内变量必须被使用,否则会报错
  • Go语言中的包内部变量可以仅仅定义和初始化,但不去使用它
func variableInitialValue(){
	// 变量初始化
	var a, b int = 3, 4
	var s string  = "Helle Go"
	fmt.Println(a, b, s)
}


包内变量是指定义和初始化在函数外,在包内的变量。其作用域在整个包内;
函数内变量是指定义和初始化在函数内的变量,作用域在函数内,不能作用在整个包内。

  1. 第三种:省略变量类型的定义和初始化
  • 省略变量定义类型,由计算机自动判断识别。这种情况下必须对变量初始化。
func variableTypeDeduction(){
	// 省略变量定义类型,由计算机自动判断识别
	var a, b, c, s = 3, 4, true, "def"
	fmt.Println(a, b, c, s)
}
  1. 第四种:省略var和变量类型的定义和初始化
  • 此方法是对变量定义和初始化时使用**:=**来操作的;
  • 不能对包内变量定义和初始化。
func variableShorter(){
	// 简单写法
	// 变量在定义时初始化即第一次对变量进行操作时用:=,这里省略关键词var
	// :=仅仅在函数内使用,在定义包内部变量时不能使用
	a, b, c, s := 3, 4, true, "shorter"
	// 第二次对变量进行操作时,就能不使用:=
	b = 5
	fmt.Println(a, b, c, s)
}


变量可以使用变量组来减少写var关键字,如下列代码

var (
	bb = 4
	gg = "Hello Go"
)
// 等效于
var bb int = 4
var gg string = "Hello Go"

数据类型之复数

  • complex64(复数,实部为32bit,虚部为32bit),complex128(复数,实部为64bit,虚部为64bit)
  • 使用欧拉公式进行举例,输出结果是实部为0,虚部是接近为0的浮点数;
func euler(){
	//c := 3 + 4i
	//// 取模
	//fmt.Println(cmplx.Abs(c))
	//使用1i表示虚部i。如果直接使用i的话,会被认为变量i而非虚部i。
	//欧拉公式 表示方法一
	fmt.Println(
		cmplx.Pow(math.E, 1i * math.Pi) + 1)
	//欧拉公式 表示方法二
	fmt.Println(
		cmplx.Exp(1i * math.Pi) + 1)
}

类型转化

  • Go语言中类型转化只有强制的,当数据类型不匹配时必须写明转化的类型;
  • 在C/C++等语言中除了强制类型转化之外,还有隐式类型转化即可以不写明类型转化,例如
int main()
{
    int a = 5;
    float b = 3;
    printf("%f",a*b);
}
  • a可以向上转型为float类型
  • Go语言中强制类型转化的例子:
func triangle(){
	var a, b int = 3, 4
	var c int
	c = int(math.Sqrt(float64(a * a + b * b)))
	fmt.Println(c)
}

常量

  • 常量的作用相当于是文本替换的作用;
func consts(){
	//// 常量的作用相当于是文本替换的作用
	//const filename =  "Goland.txt"
	//const a, b = 3, 4
	//// 这里若将a,b定义数据类型,则下面在Sqrt中需要进行强制类型转化为float64
	//// 常量const数值可以作为各种类型使用

	const ( //常量可以定义在一组中
		filename =  "Goland.txt"
		a, b = 3, 4
	)
	var c int
	c = int(math.Sqrt(a * a + b * b))
	fmt.Println(filename, c)
}

特殊的常量-枚举

  1. 对枚举中的每个元素赋值。
  • 下列代码输出结果是0 1 2 3
const(
	cpp = 0
	java = 1
	python = 2
	goland = 3
)
fmt.Println(cpp, java, python, goland)
  1. 对枚举的第一个元素赋值,并且元素可以自增
  • 使用iota给第一个元素赋值,能实现后面的元素在前一个元素的基础上自增一;
  • iota是从0开始自增的
  • 下列代码输出结果是
    10 14 12 13
    1 1024 1048576 1073741824 1099511627776 1125899906842624
const (
	cpp = iota + 10
	_
	python
	goland
	javascript
)
fmt.Println(cpp, javascript, python, goland)
// 输出结果是常量自增,不需要每个赋值

// b, kb, mb, gb, tb, pb
const (
	b = 1 << (10 * iota) //左移动10位,即扩大1024倍
	kb
	mb
	gb
	tb
	pb
)
fmt.Println(b, kb, mb, gb, tb, pb)
  1. 对枚举中的第一个元素赋值。
  • 下列代码输出结果是97 97 97。没有自增。
const (
	aa = 97
	bb
	cc
)
fmt.Println(aa, bb, cc)

条件与循环语句

条件语句

  1. 条件语句if的格式是
if 条件 {

} else if 条件{

} else {

}
  • if语句的案例
const filename = "Golang.txt"
	//contents, err := ioutil.ReadFile(filename) // 读取文件,访问文件内容byte数组和出错信息
	//if err != nil {
	//	fmt.Println(err)
	//} else {
	//	fmt.Printf("%s\n", contents)
	//}
	if contents, err := ioutil.ReadFile(filename); err != nil {
		fmt.Println(err)
	}else {
		fmt.Printf("%s\n", contents)
	}
	// if外不能使用变量contents
	// fmt.Printf("%s\n", contents) 这里contents会报错,contents生存期在if中,在if外不能使用contents
  • if的条件里可以赋值
  • if的条件里赋值的变量作用域就在这个if语句里
  1. 条件语句switch casei的格式是
switch 表达式 {
case 表达式一:
	语句一
case 表达式二:
	语句二
...
default:
}
  • Goland中switch会自动break,除非使用fallthrough

  • switch通常执行一个case后会立即退出swithc,case后的fallthrough语句表明执行完当前 case 语句之后按顺序执行下一个case 语句;

  • swithc后可以不跟表达式,相当与switch true,将case中的表达式与true比较,相等执行;

  • 多个有相同值的 case 是不允许的;

  • case后的表达式可以有多个,用逗号分隔。

  • switch语句案例

func grade(score int) string {
	g := ""
	switch  {
	case score < 0 || score > 100:
		panic(fmt.Sprintf(
			"Wrong score: %d", score))
	case score < 60:
		g = "E"
	case score < 70:
		g = "D"
	case score < 80:
		g = "C"
	case score < 90:
		g = "B"
	case score <= 100:
		g = "A"
	}
	return g
}

循环语句

循环语句for的格式

for 初始条件; 结束条件; 递增表达式 {

}

// 例
sum := 0
for i := i; i <= 100; i++ {
	sum += i
}
  • for的条件不需要括号
  • for的条件里可以省略初始条件、结束条件、递增表达式
  • 省略初始条件和递增表达式,相当于while
  • for什么都省略,相当于无限循环
// 十进制转二进制案例
func convertToBin(n int) string{
	result := ""
	for ; n > 0; n /= 2 {
		lsb := n % 2 // 取模
		result = strconv.Itoa(lsb) + result
	}
	return  result
}

条件语句和循环语句要点回顾

  1. for, if后面的条件没有括号;
  2. if条件里可以定义变量;
  3. 没有while;
  4. switch不需要break,也可以直接switch多个条件。

函数

  • 函数名在前,类型在后
  • 函数可以返回对个值
  • 函数返回多个值时可以对他们取名字,仅用于非常简单的函数
  • 函数内还可以嵌套函数,即函数可以作为参数
  • 可变参数列表,同数组一样使用
  • 没有默认参数,可选参数,函数重载等操作

函数的案例

func eval(a, b int, op string) (int, error) {
	switch op {
	case "+":
		return a + b, nil
	case "-":
		return a - b, nil
	case "*":
		return a * b, nil
	case "/":
		//return a / b
		q, _ := div(a, b) // go中定义的变量必须使用,这里使用_表明第二个字段r不想被定义出来
		return q, nil
	default:
		return 0, fmt.Errorf("unsupported operation: %s" + op)
	}
}

// 带余数除法 13 / 3 = 4 ... 1
//func div(a, b int) (int, int){
//	return a / b, a % b
//}
func div(a, b int) (q, r int){
	//q = a / b
	//r = a % b
	//return q, r
	return a / b, a % b
}


// 函数式编程
func apple(op func(int, int) int, a, b int) int {
	p := reflect.ValueOf(op).Pointer() //反射,获取指针
	opName := runtime.FuncForPC(p).Name() //获得操作的名字,通过函数名执行对应的函数
	fmt.Println("Calling function %s with args " + "(%d, %d)\n", opName, a, b)
	return op(a, b)
}
func pow(a, b int) int {
	return int(math.Pow(float64(a), float64(b)))
}

// 可变参数列表
func sum(numbers ...int) int {
	s := 0
	for i := range numbers {
		s += numbers[i]
	}
	return s
}


func main(){

	fmt.Println(
		eval(3, 4, "*"),
		)

	// 多返回值的函数
	fmt.Println(
		div(13, 3),
		)

	q, r := div(13, 3)
	fmt.Println(q, r)

	// 带error返回值的函数
	if result, err := eval(9,4, "/"); err != nil {
		fmt.Println("Error", err)
	} else {
		fmt.Println(result)
	}

	// 函数式编程一
	fmt.Println(apple(pow, 3, 4))

	// 函数式编程二 通过匿名函数来实现的
	fmt.Println(apple(
		func(a int, b int) int {
			return int(math.Pow(
				float64(a), float64(b)))
		}, 3, 4),
	)

	// 可变参数列表的案例
	fmt.Println(sum(1, 2, 3, 4, 5))
}

指针

  • Go中指针不能运算,即指针不能++或–等操作;
  • Go语言中只用值传递一种方式;
  • Go中实现引用传递需要借助指针;

指针的定义和赋值

var a int = 2
var pa *int = &a // pa指向变量a的位置
*pa = 3  // a的值为3
fmt.Println(a) // 3


值传递:将变量值拷贝一份传递给函数,在函数中无论对值传递参数怎么操作,多不会影响原来的变量;
引用传递:将变量的地址传递给函数,在函数中可以对原变量进行操作;
在java和python中除了内建类型外,自定义的函数参数一般都是应用传递。

实现引用传递案例

func swap(a, b *int) {
	*b, *a = *a, *b // 将a指向的内容和b指向的内容进行交换
}
func main() {
	a, b := 3, 4
	swap(&a, &b) // 取a,b的地址
	fmt.Println(a, b)
}

基础语法就此结束

你可能感兴趣的:(Golang)