zoukankan      html  css  js  c++  java
  • go基础一

    前言

    安装完goland,开始入坑go

    首先要有一门语言基础:java,c++等

    代码

    package main
    
    import (
    	"fmt"
    	"unsafe"
    )
    
    func main()  {
    	fmt.Println()
    
    	// 1. 变量和常量
    	// var 变量名 类型 [ = 值]
    	// 变量名 := 值
    	var c int = 4
    	a , b := 1 , "hello"
    	fmt.Println(a,b,c)
    	// Go 语言提供自动内存管理,不需要关心变量的生存期和存放位置,编译器使用栈逃逸技术能够自动为变量分配空间:可能在栈上,也可能在堆上。
    
    
    	// 2. 常量
    	//方式一 类似枚举的iota
    	const (
    		c0 = iota // c0 == 0
    		c1 = iota // c1 == 1
    		c2 = iota // c2 == 2
    	)
    	//方式二 简写模式
    	const (
    		c3 = 3 // c3 == 3
    		c4        // c4 == 3
    		c5        // c5 == 3
    	)
    	//方式三 分开的const语句
    	const x = 5 // x == 5
    	const y = iota // y == 0
    	fmt.Println(c0,x,c3,c4)
    
    
    	// 3. 数据基本类型
    	//布尔类型
    	var ok bool
    	fmt.Println(ok) //false  不初始化默认false
    	ok = true
    	fmt.Println(ok) //true
    
    	fals := false
    	fmt.Println(fals) //false
    	//整型
    	var a1 int = 1
    	var a2 int32 = 2
    	//a2  = a1 //error  不同类型的整形必须进行强制类型转换
    	fmt.Println(a2,a1)
    
    	var a3 int = (1 + 2) * 3
    	var b3 int = 1000 >> 2
    	fmt.Println(a3,b3) //9 250
    
    	//浮点类型
    	var b4 float64 = 10.02  // 用于表示包含小数数据,有两种类型分别是float32和float64 浮点数自动类型推倒位float64
    	var b5  = 10.03
    	fmt.Println(b4,b5) // 10.02 10.03
    	//计算机很难对浮点型数精确存储,两个浮点数之间不要用==或!=进行比较,高精度科学计算使用math
    
    	//复数型
    	//在计算机中使用两个浮点数表示,一个表示实部,一个表示虚部,complex64是由两个float32构成的,complex128是由两个float64构成的。复数的字面量表示和数学表示法一样。
    	var v1 complex64 = 3.1 + 5i
    	v2 := 3.1 + 6i
    	//Go有三个函数处理复数
    	var v = complex(2.1, 3) //构造一个复数
    	a6 := real(v1)           //返回复数的实部
    	b6 := imag(v2)          //返回复数的虚部
    	fmt.Println(a6,b6,v)  //3.1 6 (2.1+3i)
    
    	//字符串
    	var a7 = "hello world"
    	fmt.Println(a7)
    	var a8 = "hello,world"
    	b8 := a8[0]
    	//a8[1] = 'a' //error  字符串是常量,可以通过类似数组索引访问字节单元,但不能修改某字节的值
    	fmt.Println(b8,a8[1])  //104 101
    
    	//字符串转换为切片[]byte(s)时候要慎用,尤其是数据量较大时候,每次转换都需要赋值大量的内容
    	b7 := []byte(a7)
    	fmt.Println(b7)  //[104 101 108 108 111 32 119 111 114 108 100]
    	c7 := a7[1:]    //基于字符串创建的切片和源字符串指向相同的底层字符串数组,一样不能修改,对字符串的切片操作返回的子串仍然是string,而非slice基于字符串创建的切片和源字符串指向相同的底层字符串数组,一样不能修改,对字符串的切片操作返回的子串仍然是string,而非slice
    	fmt.Println(c7)  //ello world
    	b7_1 := []rune(a7)
    	fmt.Println(b7_1)  //字符串和切片的转换:字符串可以转换为字节数组,也可以转换为Unicode的字数组
    	//Go内置两种字符类:1.byte的字节类型;2.表示Unicode编码的字符rune。
    	//rune在Go内部是int32类型的别名,占用4个字节。
    	//Go语言默认字符编码就是UTF-8类型的,如果需要特殊的编码转换,使用Unicode/UTF-8标准包。
    
    	//字符串的运算:拼接、求长度、遍历
    	a9 := "hello"
    	b9 := "world"
    	c9 := a9 + b9	//字符串拼接
    	fmt.Println(c9)
    	fmt.Println(len(a9))	//len函数获取字符串的长度
    	d := "hello,世界"
    	//遍历字节数组
    	for i := 0; i<len(d); i++ {
    		fmt.Print(d[i])
    	}
    	//遍历rune数组
    	for i, v :=range d {
    		fmt.Print(i,v)
    	}
    	fmt.Println("==========>方法一")
    	//方法一:格式化打印  // 'h''e''l''l''o'',''世''界'
    	for _, ch1 := range d {
    		fmt.Printf("%q",ch1) //单引号围绕的字符字面值,由go语法安全的转义
    	}
    	fmt.Println("==========>方法二")
    	//方法二:转化输出格式  // hello,世界
    	for _, ch2 := range d {
    		fmt.Print(string(ch2))
    	}
    
    
    	// 指针
    	//指针的声明类型为*T, Go同样支持多级指针**T。通过在变量名前面加&来获取变量的地址。
    	//在赋值语句中,T出现在“=”左边表示指针声明,T出现在“=”右边表示取指针指向的值(varName为变量名)。
    	var a11 =11
    	p := &a11
    	fmt.Println(p)
    
    	//结构体指针访问结构体字段仍然使用“.”点操作符,Go语言没有“>”操作符。
    	type User struct {
    		name string
    		age  int
    	}
    	andes := User{
    		name: "andes",
    		age:  18,
    	}
    	pp := &andes
    	fmt.Println(pp.name) //p.name通过“.”操作符访问成员变量
    	//Go不支持指针的运算。Go由于支持垃圾回收,如果支持指针运算,则会给垃圾回收的实现带来很多不便,在C和C++里面指针运算很容易出现问题,因此Go直接在语言层面禁止指针运算。
    	//a := 1234
    	//p := &a
    	//p++ //不允许,报non-numeric type*int错误
    
    	//函数中允许返回局部变量的地址。 Go编译器使用“栈逃逸”机制将这种局部变量的空间分配在堆上。
    	//例如 sum()
    
    
    	//数组
    	//	数组的类型名是[n]类型,其中n是数组长度。比如一个包含2个int类型元素的数组类型可表示为[2]int。数组一般在创建时通过字面量初始化,单独声明一个数组类型变量而不进行初始化是没有意义的。
    	var arr [2]int                       //声明一个有两个整型的数组,但元素默认值都是0,一般很少这样使用
    	array := [...]float64{7.0, 8.5, 9.1} //[...1后面跟字面量初始化列表
    	fmt.Println(arr,array)  //[0 0] [7 8.5 9.1]
    	//数组的初始化
    	arr1 := [3]int{1, 2, 3}   //指定长度和初始化字面量
    	arr2 := [...]int{1, 2, 3} //不指定长度,但是由后面的初始化列表数量来确定其长度
    	arr3 := [3]int{1: 1, 2: 3}   //指定总长度,并通过索引值进行初始化,没有初始化元素时使用类型默认值
    	arr4 := [...]int{1: 1, 2: 3} //不指定总长度,通过索引值进行初始化,数组长度由最后一个索引值确定,没有指定索引的元素被初始化为类型的零值
    	fmt.Println(arr1,arr2,arr3,arr4) //[1 2 3] [1 2 3] [0 1 3] [0 1 3]
    	//数组的特点
    	//(1)数组创建完长度就固定了,不可以再追加元素。
    	//(2)数组是值类型的,数组赋值或作为函数参数都是值拷贝。
    	//(3)数组长度是数组类型的组成部分,[10]int和[20]int表示不同的类型。
    	//(4)可以根据数组创建切片。
    	//数组的访问
    	array1 := [...]int{1, 2, 3}
    	barray := array1[0]
    	fmt.Println(barray)
    	//数组访问一
    	for i,v := range array1 {
    		fmt.Println(i,v)
    	}
    	//数组访问二
    	alength := len(array1)
    	for i:=0; i<alength; i++ {
    		//...
    	}
    
    
    	//切片(slice)
    	//数组的定长性和值拷贝限制了其使用场景,Go提供了另一种数据类型slice(切片),这是一种变长数组,其数据结构中有指向数组的指针,所以是一种引用类型。
    	//在Go中,几乎所有场景,可以使用切片代替数组
    	type slice struct {  //Go为切片维护三个元素:指向底层数组的指针、切片的元素数量、底层数组的容量。
    		array unsafe.Pointer
    		len int
    		cap int
    	}
    	//切片创建
    	//一由数组创建
    	/**
    	创建语法array [begin:end].
    	array表示数组名;
    	begin表示开始索引,可以不指定,默认是0;
    	end表示结束索引,可以不指定,默认是len(array)。
    	array[begin:end]表示一个包含end-begin个元素的切片(切片容量),第一个元素是aray[b],最后一个元素是array[e-1]。
    	注意:按数组下标算,左闭右开,表示包含begin下表,不包含end下标
    	 */
    	var array2 = [...]int{0, 1, 2, 3, 4, 5, 6}
    	s1 :=  array2[0:4]	//[0 1 2 3]
    	s2 := array2[:4]	//[0 1 2 3]
    	s3 := array2[2:]	//[2 3 4 5 6]
    	fmt.Println(s1,s2,s3)
    	//二内置函数make创建切片
    	s4 := make([]int, 10)	//len = 10, cap = 10, 结果为[0 0 0 0 0 0 0 0 0 0]
    	s5 := make([]int, 10, 15)	//len = 10, cap = 15, 结果为[0 0 0 0 0 0 0 0 0 0]
    	fmt.Println(s4,s5)
    	//三直接声明切片类型变量
    	var s6 []int	//结果为[] 直接声明切片类型变量是没有意义的,此时切片的底层的数据结构array=nil len=0 cap=0
    	fmt.Println(s6)
    
    	//切片的操作
    	/**
    	内置函数len()返回切片长度。
    	内置函数cap()返回切片底层数组容量。
    	内置函数append()对切片追加元素。
    	内置函数copy()用于复制一个切片。
    	 */
    	s7 := [...]int{0, 1, 2, 3, 4, 5, 6}
    	s8 := make([]int, 2, 4)
    	s9 := s7[0:3]
    
    	fmt.Println(len(s8)) //2
    	fmt.Println(cap(s8)) //4
    
    	s8 = append(s8, 1)
    	fmt.Println(s8)      //[0 0 1]
    	fmt.Println(len(s8)) //3
    	fmt.Println(cap(s8)) //4
    
    	s8 = append(s8, s9...)
    	fmt.Println(s8)      //[0 0 1 0 1 2]
    	fmt.Println(len(s8)) //6
    	fmt.Println(cap(s8)) //cap(b)=8,底层数组发生扩展
    
    	s10 := make([]int, 2, 2)
    	copy(s10, s9)          //copy只会复制d和c中长度最小的
    	fmt.Println(s10)      //[0 1]
    	fmt.Println(len(s10)) //2
    	fmt.Println(cap(s10)) //2
    
    	//注意:向切片增加元素时,切片的容量会自动增长。1024 以下时,一两倍方式增长。
    	str := "hello world"
    	s11 := []byte(str)	///将字符串转换为[]byte类型切片
    	s12 := []rune(str)	//将字符串转换为[]rune类型切片
    	fmt.Println(s11,s12)
    
    
    	//字典 map
    	//Go语言内置的字典类型叫map。map的类型格式是:map[K]T,其中K可以是任意可以进行比较的类型,T是值类型。map也是一种引用类型。
    	//map的创建
    	//一使用字面量创建
    	ma := map[string]int {"a":1,"b":2}
    	fmt.Println(ma["a"])
    	fmt.Println(ma["b"])
    	//二使用内置make创建
    	mpl := make(map[int]string)
    	mp2 := make(map[int]string , 10)
    	mpl[1] = "tom"
    	mp2[1] = "pony"
    
    	// amp操作
    	//map的单个键值访问格式为mapName[key],更新某个key的值时mapName[key]放到等号左边,访问某个key的值时mapName[key]放在等号的右边。
    	//可以使用range遍历一个map类型变量,但是不保证每次迭代元素的顺序。
    	//删除map中的某个键值,使用如下语法:delete(mapName,key)。delete是内置函数,用来删除map中的某个键值对。
    	//可以使用内置的len()函数返回map中的键值对数量。
    	mp := make(map[int]string)
    	mp[1] = "tom"
    	mp[2] = "pony"
    	mp[3] = "jaky"
    	delete(mp, 3)
    	fmt.Println(len(mp)) //2
    	for k, v := range mp {
    		fmt.Println("key=", k, "value=", v)
    	}
    	//注意:
    	//Go内置的map不是并发安全的,并发安全的map可以使用标准包sync中的map。
    	//不要直接修改map value内某个元素的值,如果想修改map的某个键值,则必须整体赋值。
    	type User2 struct {
    		name string
    		age  int
    	}
    	ma1 := make(map[int]User2)
    	andes1 := User2{
    		name: "andes",
    		age:  18,
    	}
    	ma1[1] = andes1
    	//ma[1].age = 19 //ERROR ,不能通过 map 引用直接修改
    	andes1.age = 19
    	ma1[1] = andes1           //必须整体替换 value
    	fmt.Printf(" %v
    ", ma1) //map[1:{andes 19}]
    
    
    	//结构体(struct)
    	//Go中的struct类型和C类似,由多个不同类型元素组合而成。这里面有两层含义:
    	//第一,struct结构中的类型可以是任意类型;第二,struct的存储空间是连续的,其字段按照声明时的顺序存放(注意字段之间有对齐要求)。
    	//struct有两种形式:
    	//一种是struct 类型字面量;另一种是使用type声明的自定义struct类型。
    	//struct {
    	//    FeildName FeildType
    	//    FeildName FeildType
    	//    FeildName FeildType
    	//}
    
    	//实际使用struct字面量的场景不多,更多的时候是通过type自定义一个新的类型来实现的。
    	//type是自定义类型的关键字,不但支持struct类型的创建,还支持任意其他子定义类型的创建。
    	type Person struct {
    		Name string
    		Age  int
    	}
    
    	type Student struct {
    		*Person
    		Number int
    	}
    
    	//不推荐这种初始化方式,一旦truct加字段,则整个初始化语句会报
    	pe := Person{"Tom", 21}
    	fmt.Println(pe)
    	//推荐这种使用 Feild 名字的初始化方式,没有指定的字段则默认初始化为类型的零值
    	per := &Person{
    		Name: "tata",
    		Age:  12,
    	}
    	stu := Student{
    		Person: per,
    		Number: 110,
    	}
    	fmt.Println(stu)
    
    
    	//控制结构
    	/**
    	现代计算机存储结构无论“普林斯顿结构”,还是“哈佛结构”,程序指令都是线性地存放在存储器上。程序执行从本质上来说就是两种模式:顺序和跳转。
    	顺序就是按照程序指令在存储器上的存放顺序逐条执行。
    	跳转就是遇到跳转指令就跳转到某处继续线性执行。
    	顺序在Go里面体现在从main函数开始逐条向下执行,就像我们的程序源代码顺序一样;跳转在Go里面体现为多个语法糖,包括goto语句和函数调用、分支(if、switch、select)、循环(for)等。
    	跳转分为两种:一种是无条件跳转,比如函数调用和goto语句;一种是有条件的跳转,比如分支和循环。
    	 */
    	//if 语句
    	/**
    	if后面的条件判断子句不需要用小括号括起来。
    	{必须放在行尾,和if或if else放在一行。
    	if后面可以带一个简单的初始化语句,并以分号分割,该简单语句声明的变量的作用域是整个if语句块,包括后面的else if和else分支。
    	Go语言没有条件运算符(a>b?a:b),这也符合Go的设计哲学,只提供一种方法做事情。
    	if分支语句遇到return后直接返回,遇到break则跳过break下方的if语句块。
    	 */
    
    	//switch 语句
    
    	//for 语句
    	//for 语句对数组、切片、字符串、map、通道的访问
    	//访问map
    	/**
    	for key, value := range map {}
    	for key := range map {}
    
    	//访问数组
    	for index, value := range array {}
    	for index := range array {}
    	for _, value := range array {}
    
    	//访问切片
    	for index, value := range slice {}
    	for index := range slice {}
    	for _, value := range slice {}
    
    	//访问通道
    	for value := range channel {}
    
    	 */
    
    
    
    	// 标签和跳转
    	// Go 语言使用标签(Lable)来标识一个语句的位置,用于goto、break、continue 语句的跳转,标签的语法是Lable:Statement
    	//goto Lable的语义是跳转到标签名后的语句处执行,goto语句有以下几个特点:
    	//goto语句只能在函数内跳转。
    	//goto语句不能跳过内部变量声明语句,这些变量在goto语句的标签语句处又是可见的。例如:
    
    	//goto 语句只能跳到同级作用域或者上层作用域内,不能跳到内部作用域内。
    
    
    	// break
    	// continue
    
    
    
    
    
    
    
    
    }
    func sum(a, b int) *int {
    	sum := a + b
    	return &sum //允许,sum会分配在heap上
    }
    

      

     参考

    https://www.cnblogs.com/WindSun/p/12208321.html

    https://blog.csdn.net/linshuhe1/article/details/73331200

  • 相关阅读:
    【WPF】操作RichTextBox(取值、赋值、清空、滚动条自动滚动实例、文本自动滚动实例)
    系统初始化 服务列表
    多个filter如何决定调用顺序
    IE浏览器 查看Form对象
    java try_catch 分析
    关于ClassLoader 和Class的俩个记录
    lis分析之一一批处理(任务)如何连接数据库的
    document.all("div).style.display = "none"与 等于""的区别
    Mybatis Util包
    Spring创建bean对象的三种方式
  • 原文地址:https://www.cnblogs.com/pergrand/p/13189260.html
Copyright © 2011-2022 走看看