2-Go 程序结构

本文详细介绍了Go语言的特性,包括内存管理中的GC、变量声明与初始化,特别是变量的生存周期和分配位置。讨论了短变量声明、指针以及变量的赋值规则。同时,讲解了条件语句、循环结构和switch的使用。还涉及了包的导入、初始化以及包级别的变量。通过对Go语言这些核心概念的解析,帮助读者深入理解Go的编程方式。
摘要由CSDN通过智能技术生成

0. Go的一些特性

  • 拥有 GC (Garbege Collection)不需要考虑手动管理内存。
  • 不需要分号做语句结尾。
  • 语言级别的并发。
  • 简洁、优雅,代码风格统一。

1.变量

  • 定义的变量必须使用。确实不需要的需要显示忽略,使用_
  • 变量声明顺序与 C/C++ 相反,先名称后类型。
  • 变量区分大小写。第一个字母的大小写决定其可见性是否跨包。
  • 变量命名风格:驼峰命名风格。
  1. 声明变量
    给一个程序实体命名,并且设定其部分或者全部属性。主要有4个:变量(var)、常量(const)、类型(type)和函数(func)。与定义的含义一样,二者不做严格区分。

    包级别的变量初始化在 main 函数开始之前进行。Go 中不存在未初始化的变量。

    声明变量:

    //1.使用 var 关键字
    var a, b, c bool
    var s1, s2 string = "hello", "world"
    
    //2.自动类型推导
    var a, b, c, i, s = true, false, 3, 2.333, "hello"
    
    //3.短变量(只能在函数内部定义)
    a, b, c := 1, true, "Hi"	
    

    指针变量(不能进行算术运算):保存变量的地址

    x := 1
    p := &x //p 是整型的指针,指向 x
    *p = 2 // x 此时为2
    

    swap 函数:

    package main
    
    import "fmt"
    
    func swap(a, b int){
    	a, b = b, a
    }
    
    func swapByPointer(a, b *int) {
    	*a, *b = *b, *a
    }
    
    func main() {
    	a, b := 1, 2
    	fmt.Printf("before swap, a:%d, b:%d\n", a, b)
    	swap(a, b)
    	fmt.Printf("after swap, a:%d, b:%d\n", a, b) //未交换
    
    	swapByPointer(&a, &b)
    	fmt.Printf("after swapByPointer, a:%d, b:%d\n", a, b) //交换成功
    }
    

    注意,函数,if 语句的花括号

    //错误的函数声明,花括号必须与 func 放在同一行
    func test()
    {
    }
    

2.变量到底分配在了哪里:栈 or 堆?
变量内存空间到底是分配在栈上还是堆上,由编译器来自行决定。

  • 如果函数外部没有引用,则优先放到栈中;
  • 如果函数外部存在引用,则必定放到堆中;
    C 语言的例子:返回局部变量的地址,p指向了一个非法的地址,因为 test 函数中 a 变量的生命周期已然结束。
#include <stdio.h>
int* test(void){
	int a = 10;
	return &a;
}
int main(void){
	int *p = test();
	printf("%d\n", *p); // 程序 core 掉
	return 0;
}

Go 的例子:

package main

import "fmt"

var global *int

func f(){
	var x int      // x 使用堆空间内存,由编译器来做
	x = 1
	global = &x
}

func g(){
    y := new(int) //y 使用栈内存,因为无外部引用,即变得不可达,可回收。
    *y = 1
}

func main() {
    f()           			 //调用 f() 给global赋值
    fmt.Println(*global)	// x 从 f() 中逃逸, global 引用了 x 
}

3.变量到底可以存活多久(变量的生命周期)?
通过变量是否可达来确定它的生命周期

  • 包级别变量:整个程序的执行时间。
  • 局部变量:动态生命周期。执行时创建,一直生存到不可访问,空间被回收,生命终结。

2.赋值、多重赋值和可赋值性

  • 直接赋值或通过指针间接赋值
  • 多个变量可以一起赋值
    a, b, c := 1, 2.2, "hello"
  • 赋值时类型必须精准匹配,nil 可以被赋给任何接口或者引用变量
	var a int = 10
	var b int64 = 20
	//a = b, error 类型不匹配
	//b = a, error 类型不匹配

3.条件

func bounded(v int) int{
	//if 语句可以没有圆括号,但必需要有花括号
	if v > 100{
		return 100
	}else if (v < 0) {
		return 0
	}else {
		return v
	}
}

4.循环

循环,只有 for 循环一种,无 while 和 do…while

	//经典的for语句 init; condition; post
	for i := 10; i < 10; i++{
		//do something
	}
    //精简的for语句 condition,  while(i < 10){ ... } 
	i := 6
	for i < 10{
		//do something
	}

	//forever for(;;)
	for{
		//do something
	}

5.switch

switch中不需要写 break,默认就会 break
注意 switch 中的 fallthrough 会无条件的进入下一个 case 中

package main

import (
	"fmt"
)

func main() {
	a := 10
	switch {
	case a > 10:
		fmt.Println("a > 1")
	case a > 2:
		fmt.Println("a > 2")
		fallthrough //无条件进入下一个 case
	case a > 30:
		fmt.Println("a > 30")
	default:
		fmt.Println("a")
	}
}

6.包和文件

  • 包和文件以及包的导入
    Go语言中的包的作用和其他语言中库和模块的作用类似(如JAVA中的包,C++中的 namespace)。
    每个包给它的声明提供独立的命名空间。
    Go语言中每个包通过导入路径的唯一字符串来标识。包名按照约定时导入路径的最后一段。
    gopl.io/ch2/tempconv 的包名就是 tempconv
    导入一个没有被引用的包,会触发错误。
    导入包时,导入的是路径而不是包名。

  • 包初始化
    包级别变量 => 执行 init() 函数
    import _ “fmt” 匿名导入 fmt 包,无法使用当前包的方式,会执行 init() 方法。
    import abc “fmt” 给 fmt 包起一个别名叫做 abc。
    import . “fmt” 将 fmt 包中的方法导入当前包作用域中,直接调用不再需要指明 fmt 。

《Go程序设计语言》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值