Go程序的基本结构
***func init() 会在main函数之前执行
1.包中的函数调用
a.同一个包中函数,直接调用
b.不同包中函数,通过包名+点+函数名进行调用
2.包的访问控制规则
a.大小写意味着这个函数/变量是可导出的
b.小写意味着这个函数/变量是私有的,包外部不能访问
练习题一:
写一个程序,对于给定一个数字n,求出所有两两相加等于n的组合。
比如: 对于n=5,所有组合如下所示:
0+5=5
1+4=5
2+3=5
3+2=5
4+1=5
5+0=5
package main import ( "fmt" ) //两个数加和,遍历一个数然后另外一个数就是和减去当前值 func list(n int){ for i := 0; i <= n ; i++ { fmt.Printf("%d+%d=%d ",i,n -i ,n) } } func main() { list(10) } /* 0+10=10 1+9=10 2+8=10 3+7=10 4+6=10 5+5=10 6+4=10 7+3=10 8+2=10 9+1=10 10+0=10 */
练习题二:
包别名的应用,开发一个程序,使用包别名来访问包中的函数?
package main import( a "add" //设置别名 ) func main () { fmt.Println("result:", a.Name) fmt.Println("result:", a.age) }
init的加载顺序
package main import "fmt" var a string = "xxxxx" //加载顺序:先初始化全局变量,在初始化init,在执行main var age int = 100 func init(){ a = "xx" age = 10 } func main() { fmt.Println("a",a,"age",age) }
main函数引入包的加载顺序(包中导入包):
程序的初始化和执行都起始于main
包。如果main
包还导入了其它的包,那么就会在编译时将它们依次导入。有时一个包会被多个包同时导入,那么它只会被导入一次(例如很多包可能都会用到fmt
包,但它只会被导入一次,因为没有必要导入多次)。当一个包被导入时,如果该包还导入了其它的包,那么会先将其它包导入进来,然后再对这些包中的包级常量和变量进行初始化,接着执行init
函数(如果有的话),依次类推。等所有被导入的包都加载完毕了,就会开始对main
包中的包级常量和变量进行初始化,然后执行main
包中的init
函数(如果存在的话),最后执行main
函数
包只初始化 不引用
_操作其实是引入该包,而不直接使用包里面的函数,而是调用了该包里面的init函数。
package main import ( _ "fmt" //下划线加空格 只初始化 不引用 ) func main() { }
Go中的常量const
永远只读,不可以被修改
***最后一个const c = getValue()是不可以的,因为函数的返回值不确定
练习:
定义两个常量Man=1和Female=2,获取当前时间的秒数,如果能被Female整除,则在终端打印female,否则打印man
package main import ( "time" "fmt" ) const ( Man = 1 Female = 2 ) func main() { Second := time.Now().Unix() if (Second % Female == 0){ fmt.Println("female",Female) }else { fmt.Println("man",Man) } }
Go变量
1.int初始值为0
2. string初始值为""
3.bool初始值为false
练习:
获取操作系统和path
package main import ( "os" "fmt" ) func main(){ var goos string = os.Getenv("GOOS") fmt.Printf("The operating system is %s ",goos) path := os.Getenv("PATH") fmt.Printf("Path is %s " ,path) }
32位操作系统指针是4字节,64位操作系统指针是8字节
值类型与引用类型
1.值类型,int,float,bool,string,数组和struct(结构体)
2.引用类型,指针,slice(切片),map,chan都是引用类型
package main import ( "fmt" ) func main() { a := 5 b := make(chan int,1) fmt.Println("a= ",a) fmt.Println("b= ",b) } /* a= 5 b= 0xc420050070 */
练习:
package main import ( "fmt" ) func modify(a int){ a = 10 //函数属于值类型 return } func modify1(p *int) { *p = 100 //指针是引用类型 所有会改变 } 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) } /* a= 5 b= 0xc420050070 a= 5 a= 100 */
练习:
将first和second值交换(通过指针改变内存地址后的源数据)
package main import ( "fmt" ) func swap(a *int,b *int){ tmp := *a *a = *b *b = tmp } func main() { first :=100 second :=200 swap(&first,&second) fmt.Println("first= ",first) fmt.Println("second= ",second) } /* first= 200 second= 100 */
第二种方法:
package main import ( "fmt" ) func swap1(a int,b int) (int,int) { return b,a } func main() { first :=100 second :=200 //swap(&first,&second) first,second = swap1(first,second) fmt.Println("first= ",first) fmt.Println("second= ",second) } /* first= 200 second= 100 */
局部变量和全局变量使用
package main import ( "fmt" ) var a string = "M" //定义了个全局变量 func main() { a := "G" //局部变量 fmt.Println("from main",a) //找自己的局部变量 f1() } func f2() { fmt.Println("from f2",a) //局部变量没有,找全局的a } func f1(){ a:="O" fmt.Println("from f1",a) f2()//执行f2函数相当于重新引用不会继承自己的局部变量 }
/*GOM*/
***重点观察
package main import ( "fmt" ) var a = "G" func main() { n() m() n() } func n (){ fmt.Println(a) } func m (){ a = "O" //将a赋值成O,因为m中未定义a所以修改的是全局的a fmt.Printf(a) } /* GOO */
***重点观察
package main import ( "fmt" ) var a string //定义了个全局变量 func main() { a = "G" //局部变量,因为当前未生命a变量,所以修改的是全局的a fmt.Println("from main",a) //找自己的局部变量 f1() } func f2() { fmt.Println("from f2",a) //局部变量没有,找全局的a,这是全局的a已经被更改为G } func f1(){ a:="O" //重新在函数内声明var a string = "O" fmt.Println("from f1",a) f2()//执行f2函数相当于重新引用不会继承自己的局部变量 } /* GOG */
数据类型和操作符
1.int8和uint8的区别?
uint8是无符号int,比int少一位 符号如:"+","-"
2.不同类型可以转换例子如下:
package main import ( "fmt" ) func test() { var a int8 = 100 var b int16 = int16(a) //将a的int8转换成int16赋值给b fmt.Printf("a=%d , b=%d" , a,b) } func main() { test() }
3.int32是4字节,int64是8字节
练习
使用math/rand生成10个随机整数,10个小于100的随机整数,10个随机浮点数
package main import ( "math/rand" "fmt" "time" ) func init(){ //放到初始化里 rand.Seed(time.Now().UnixNano()) //以时间戳做为当前随机数的种子,Nano是纳秒 } func main() { for i := 0 ; i < 10 ; i++ { a := rand.Int() //获取整数 fmt.Println(a) } for i := 0 ;i < 10 ; i++{ a := rand.Intn(100) //获取100以内的随机整数 fmt.Println(a) } for i := 0 ; i < 10 ; i++ { a := rand.Float32() //获取浮点数 fmt.Println(a) } }
字符和字符串
1.字符byte var a byte = 'c' 一个byte占用1个字节 8位 ***字符必须是单引号
2.字符串由多个字符组成
3.字符串""与``的区别
``可以保存原有格式原封不动打印
package main import "fmt" func main() { var str = "hello world " var str1 = ` go go go , 1231 123 ` var b byte = 'c' fmt.Println(str) fmt.Println(str1) fmt.Println(b) //默认是数字标识 fmt.Printf("%c ",b) //字符格式化输出 } /* hello world go go go , 1231 123 99 c */
fmt格式化输出详解
/* 一般: %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 无小数部分的,指数为二的幂的科学计数法,与 strconv.FormatFloat 的 'b' 转换格式一致。例如 -123456p-78 %e 科学计数法,例如 -1234.456e+78 %E 科学计数法,例如 -1234.456E+78 %f 有小数点而无指数,例如 123.456 %g 根据情况选择 %e 或 %f 以产生更紧凑的(无末尾的0)输出 %G 根据情况选择 %E 或 %f 以产生更紧凑的(无末尾的0)输出 字符串与字节切片: %s 字符串或切片的无解译字节 %q 双引号围绕的字符串,由Go语法安全地转义 %x 十六进制,小写字母,每字节两个字符 %X 十六进制,大写字母,每字节两个字符 指针: %p 十六进制表示,前缀 0x */ package main import "fmt" func main() { var a int = 100 var b bool c := 'a' fmt.Printf("%v ",a) //相应值的默认格式。在打印结构体时 fmt.Printf("%#v ",b) fmt.Printf("%T ",c) //相应值的类型的Go语法表示 fmt.Printf("90%% ") //百分比 fmt.Printf("%b ",a) //二进制显示 fmt.Printf("%f ",199.22) //浮点数显示 fmt.Printf("%q ","this is a str") //单引号围绕的字符字面值,由Go语法安全地转义 fmt.Printf("%p ",&a) //打印内存地址 //将一个int类型转化成str 不能用强制转换 str := fmt.Sprintf("%d",a) fmt.Printf("%q ",str) } /*
result: 100 false int32 90% 1100100 199.220000 "this is a str" 0xc42007e008 "100" */
用Go实现字符串反转
package main import "fmt" func reverse(str string) (string){ var result string strLen := len(str) for i := 0 ; i < strLen; i++ { result = result + fmt.Sprintf("%c",str[strLen -i -1]) } return result } func main() { myStr:= "hello world" result := reverse(myStr) fmt.Println(result) } /* dlrow olleh */
通过数组反转
package main import "fmt" func reverse_arry(str string) (string){ var result []byte //定义一个空数组 length := len(str) for i := 0 ; i < length ; i++ { result = append(result,str[length -i -1]) //通过append往数组里追加值 } return string(result) //最后在string化 } func main() { myStr:= "hello world" result = reverse_arry(myStr) fmt.Println(result) }
Go的字符串操作
package main import "fmt" func main() { str := "hello" str1 := "world" //result := str + " " +str1 result := fmt.Sprintf("%s %s", str, str1) //字符串拼接 q := result[6:] //字符串切片 fmt.Println(result) fmt.Println(q) } /* hello world world */
练习:
求100到200的素数,用户随便输入
package main import ( "fmt" "math" ) func isPrime(n int ) bool{ for i := 2 ; i < int(math.Sqrt(float64(n))) ; i++ { //素数是大于1的自然数除了1和他本身不能有其他整除,类似于奇数 if n % i == 0 { return false } } return true } func main() { var n int var m int fmt.Scanf("%d%d",&n,&m) //类似于python的input输入,传入Scanf函数是指针,这样就可以确保函数外定义的变量可以修改值 for i := n ; i < m ; i++ { if isPrime(i) == true{ fmt.Printf("%d ",i) continue } } }
打印出100-999中所有的“水仙花数”,所谓“水仙花数”是指一个三位数,其各位数字立方和等于该数本身。例如:153 是一个 “水仙花数”,因为 153=1 的三次方+5 的三次方+3 的三次方
package main import "fmt" func isNumber(num int) bool{ a := num % 10 b := (num / 10) % 10 c := (num / 100) % 10 res := a*a*a + b*b*b + c*c*c return res == num } func main() { var n int var m int fmt.Scanf("%d%d",&n,&m) for i := n ; i < m ; i ++ { if isNumber(i) == true{ fmt.Println("this is a shuixianhua = ",i) } } } /* 1 999 this is a shuixianhua = 1 this is a shuixianhua = 153 this is a shuixianhua = 370 this is a shuixianhua = 371 this is a shuixianhua = 407 */
通过ascii码实现水仙花:
package main import ( "fmt" "strconv" ) func main() { var str string fmt.Scanf("%s" ,&str) var result = 0 for i := 0 ; i < len(str) ; i++ { sum := int(str[i] - '0') //字符串切片默认是ascii码,通过ascii与0做运算 0代表48(十进制),1代表49(十进制)做差仍为1 result += (sum * sum * sum) } number,err := strconv.Atoi(str) //将字符串转化为int if (err != nil) { fmt.Printf("cat not convert %s to int ",number) return } if result == number{ fmt.Printf("%d is shuixianhua ",number) }else{ fmt.Printf("%d is not shuixianhua " ,number) } }
对于一个数n,求n的阶乘之和,即: 1! + 2! + 3!+...n!
package main import "fmt" func sum(n int ) uint64{ var s uint64 = 1 var sum uint64 = 0 for i := 1; i <= n ; i++ { s = s * uint64(i) //和乘以当前值 就是下一位阶乘的结果 fmt.Printf("%d!=%v ",i,s) sum += s //这是阶乘的和 } return sum } func main() { var n int fmt.Scanf("%d", &n) s := sum(n) fmt.Println(s) } /* 10 1!=1 2!=2 3!=6 4!=24 5!=120 6!=720 7!=5040 8!=40320 9!=362880 10!=3628800 4037913 */