基于Java基础学习Golang——先大致过一遍(持续更新)

这篇博文是我持续学习Golang时的个人总结

官网下载msi后缀的64位程序后,像Java一样把bin目录追加到环境变量PATH中即可
IDE使用JetBrains GoLand
Go语言现在叫Golang

Hello world:
main方法必须放在main包下,否则编译出错

package main

import "fmt"

var age  = 1
var id int = 1
var num int

func main() {
	fmt.Println("Hello, world; こんにちは世界")
	println(age, id, num)
}

变量
由数字、字母、下划线组成,首个字符不能是数字
var identifier type
三种定义方法:
var age = 1//根据值自行判定变量类型

var id int = 1

var g ,h int //分开的方式只能用在局部变量里
g, h = 1, 2

初始化声明(a := 20):
这种方式只能使用在函数体中
我自己感觉可以养成习惯,全局变量用var定义(JavaScript是局部变量用var别搞混淆了),局部变量用初始化声明a := 20的方式!

注意在代码块中
1.如果你声明了一个局部变量却没有在相同的代码块中使用它,会得到编译错误
2.不能对相同名称的变量再次使用初始化声明(a := 20),但是 a = 20 是可以的,因为这是给相同的变量赋予一个新的值。

当使用等号 = 将一个变量的值赋值给另一个变量时,如 j = i,实际上是在内存中将 i 的值进行了拷贝

更复杂的数据通常会需要使用多个字,这些数据一般使用引用类型保存。
这个内存地址称之为指针,这个指针实际上也被存在另外的某一个字中。
同一个引用类型的指针指向的多个字可以是在连续的内存地址中(内存布局是连续的),这也是计算效率最高的一种存储形式;也可以将这些字分散存放在内存中,每个字都指示了下一个字所在的内存地址。

常量:

const LENFTH int = 10
const WIDTH int = 5
var area int
const a, b, c = 1, 2, 3
area = LENFTH * WIDTH

还可用作枚举

const (
    Unknown = 0
    Female = 1
    Male = 2
)

常量可以用len(), cap(), unsafe.Sizeof()函数计算表达式的值。常量表达式中,函数必须是内置函数,否则编译不通过

iota用法:
第一个 iota 等于 0,每当 iota 在新的一行被使用时,它的值都会自动加 1,所以 a=0, b=1, c=2 可以简写为:

const (
    a = iota
    b
    c
)

——

func main() {
    const (
            a = iota   //0
            b          //1
            c          //2
            d = "ha"   //独立值,iota += 1
            e          //"ha"   iota += 1
            f = 100    //iota +=1
            g          //100  iota +=1
            h = iota   //7,恢复计数
            i          //8
    )
    fmt.Println(a,b,c,d,e,f,g,h,i)
}
//结果为:0 1 2 ha ha 100 100 7 8,常量赋值会继承上面的表达式

* 指针变量
& 返回变量存储地址 &a 将给出变量的实际地址。
*a 是一个指针变量

 func main() {
    	var a int = 6
    	var ptr *int
    	ptr = &a
    	fmt.Printf("a的值为 %d\n", a) //6
    	fmt.Printf("*ptr为 %d\n", *ptr) //6
    }//后面会有详细的解释

注意go语言的for后面没有(),if后面有()

对于go来说是值传递可以直接有swap()方法

func max(num1, num2 int) int {
   var result int
   if num1 > num2 {
      result = num1
   } else {
      result = num2
   }
   return result
}

func swap(x, y string) (string, string) {
   return y, x
}

func main1() {
   a := 10
   b := 20
   var ret int
   ret = max(a, b)
   fmt.Printf("最大的值是:%d", ret)
}
func main() {
   a, b := swap("Bob", "Sam")
   fmt.Println(a, b)
}

函数作为值:
函数定义后可作为值来使用:

func main(){
   /* 声明函数变量 */
   getSquareRoot := func(x float64) float64 {
      return math.Sqrt(x)
   }

   /* 使用函数 */
   fmt.Println(getSquareRoot(9))
}

函数闭包:
Go 语言支持匿名函数,可作为闭包。匿名函数是一个"内联"语句或表达式。匿名函数的优越性在于可以直接使用函数内的变量,不必申明。

func getSequence() func() int {
   i:=0
   return func() int {
      i+=1
     return i  
   }
}

func main(){
   /* nextNumber 为一个函数,函数 i 为 0 */
   nextNumber := getSequence()  

   /* 调用 nextNumber 函数,i 变量自增 1 并返回 */
   fmt.Println(nextNumber())
   fmt.Println(nextNumber())
   fmt.Println(nextNumber())
   
   /* 创建新的函数 nextNumber1,并查看结果 */
   nextNumber1 := getSequence()  
   fmt.Println(nextNumber1())
   fmt.Println(nextNumber1())
} // 1 2 3 1 2

对于for循环:

切记如果在for循环外用var a = 0定义了一个a ,for初始化用a := 0定义了a,for循环结束后在循环外面打印a的时候还是0,如果想让外面的a打印的结果就是a循环时的变化,则循环初始化用a = 0定义(因为a := 0这样的定义仅仅只是局部的

数组:
定义方式:

//第一种
//var <数组名称> [<数组长度>]<数组元素>
var arr [2]int
    arr[0]=1
    arr[1]=2

//第二种
//var <数组名称> = [<数组长度>]<数组元素>{元素1,元素2,...}
var arr = [2]int{1,2}
//或者
arr := [2]int{1,2}

//第三种
//var <数组名称> [<数组长度>]<数组元素> = [...]<元素类型>{元素1,元素2,...}
var arr = [...]int{1,2}
//或者
arr := [...]int{1,2}

//第四种
//var <数组名称> [<数组长度>]<数组元素> = [...]<元素类型>{索引1:元素1,索引2:元素2,...}
var arr = [...]int{1:1,0:2}
//或者
arr := [...]int{1:1,0:2}
func main() {
   var a = [5]int{1,2,3,4,5}
   var b = a[0]
   fmt.Println(b)
   var c = [5][2]int{ {0,0}, {1,2}, {2,4}, {3,6},{4,8}}
   d := c[1][1]
   fmt.Print(d)
}

指针:
* 号用于指定变量是作为一个指针
在已经是指针类型前面加上 * 号(前缀)来获取指针所指向的内容

一个指针变量指向了一个值的内存地址这句话体现在定义和形参中
var ptr *int = &a

func main() {
   var a int= 20   /* 声明实际变量 */
   var ip *int        /* 声明指针变量 */

   ip = &a  /* 指针变量的存储地址 */

   fmt.Printf("a 变量的地址是: %x\n", &a  )

   /* 指针变量的存储地址 */
   fmt.Printf("ip 变量储存的指针地址: %x\n", ip )

   /* 使用指针访问值 */
   fmt.Printf("*ip 变量的值: %d\n", *ip )
}

指针数组:

func main() {
	//a := [3]int{10,100,1000}
	//for i := 0; i < len(a); i++ {
	//	fmt.Println(a[i])
	//}
	const MAX int = 3
	a := [3]int{1, 2, 3}
	var ptr [MAX]*int

	for i := 0; i < MAX; i++ {
		ptr[i] = &a[i]
	}
}
//a[0] = 1 a[1] = 2 a[2] = 3

指向指针的指针:

func main() {
   var a int
   var ptr *int
   var pptr **int

   a = 3000

   /* 指针 ptr 地址 */
   ptr = &a

   /* 指向指针 ptr 地址 */
   pptr = &ptr

   /* 获取 pptr 的值 */
   fmt.Printf("变量 a = %d\n", a )
   fmt.Printf("指针变量 *ptr = %d\n", *ptr )
   fmt.Printf("指向指针的指针变量 **pptr = %d\n", **pptr)
} 
//变量 a = 3000
//指针变量 *ptr = 3000
//指向指针的指针变量 **pptr = 3000

指针作为函数参数:

func main() {
   /* 定义局部变量 */
   var a int = 100
   var b int= 200

   fmt.Printf("交换前 a 的值 : %d\n", a )
   fmt.Printf("交换前 b 的值 : %d\n", b )

   /* 调用函数用于交换值
   * &a 指向 a 变量的地址
   * &b 指向 b 变量的地址
   */
   swap(&a, &b);

   fmt.Printf("交换后 a 的值 : %d\n", a )
   fmt.Printf("交换后 b 的值 : %d\n", b )
}
func swap(x *int, y *int){
    *x, *y = *y, *x
}

func swap(x *int, y *int) {
   var temp int
   temp = *x    /* 保存 x 地址的值 */
   *x = *y      /* 将 y 赋值给 x */
   *y = temp    /* 将 temp 赋值给 y */
}

结构体(类似于自定义对象):

import "fmt"

type Books struct {
   title string
   author string
   subject string
   book_id int
}

func main() {
   var Book1 Books        /* 声明 Book1 为 Books 类型 */
   var Book2 Books        /* 声明 Book2 为 Books 类型 */

   /* book 1 描述 */
   Book1.title = "Go 语言"
   Book1.author = "www.runoob.com"
   Book1.subject = "Go 语言教程"
   Book1.book_id = 6495407

   /* book 2 描述 */
   Book2.title = "Python 教程"
   Book2.author = "www.runoob.com"
   Book2.subject = "Python 语言教程"
   Book2.book_id = 6495700

   /* 打印 Book1 信息 */
   printBook(Book1)

   /* 打印 Book2 信息 */
   printBook(Book2)
}
//结构体作为函数参数
func printBook( book Books ) {
   fmt.Printf( "Book title : %s\n", book.title);
   fmt.Printf( "Book author : %s\n", book.author);
   fmt.Printf( "Book subject : %s\n", book.subject);
   fmt.Printf( "Book book_id : %d\n", book.book_id);
}

结构体指针看明白使用方式:
先func printBook( book *Books )
再printBook(&Book2)
//还是指针变量指向了值的内存地址的使用方式

Go 语言函数方法
Go 语言中同时有函数和方法。一个方法就是一个包含了接受者的函数,接受者可以是命名类型或者结构体类型的一个值或者是一个指针。所有给定类型的方法属于该类型的方法集(自己重点用下面的例子体会这句话)。语法格式如下:

func (variable_name variable_data_type) function_name() [return_type]{
   /* 函数体*/
}
下面定义一个结构体类型和该类型的一个方法:

package main

import (
   "fmt"  
)

/* 定义结构体 */
type Circle struct {
  radius float64
}

func main() {
  var c1 Circle
  c1.radius = 10.00
  fmt.Println("圆的面积 = ", c1.getArea())
}

//该 method 属于 Circle 类型对象中的方法
func (c Circle) getArea() float64 {
  //c.radius 即为 Circle 类型对象中的属性
  return 3.14 * c.radius * c.radius
} //圆的面积 =  314

切片:

数组: a := [...]int{1,2,3}   a := [3]int{1,2,3}

切片: a:= []int{1,2,3}  a := make([]int, 5) a := make([]int, 5, 10)

//var a [...]int = [...]int{1, 2, 3} //error就算数组能自动推断长度也不能这么写
a := [...]int{1, 2, 3}
var a2 [3]int = [3]int{4, 5, 6}

//通过切片s初始化切片s1
s1 := s[startIndex:endIndex]

通过内置函数==make()==初始化切片s(该函数有三个参数,第一个参数是类型,第二个参数是分配的空间,第三个参数是预留分配空间),[]int 标识为其元素类型为int的切片,原来预留的空间需要重新切片才可以使用

func main(){
	a := make([]int, 10, 20)
	//就是说你预留了20的空间但也要重新切片才能使用
	fmt.Printf("%d, %d\n", len(a), cap(a))
	fmt.Println(a)
	b := a[:cap(a)]
	fmt.Println(b)
}

注意make()里第三个容量参数的计算:
基于原数组或者切片创建一个新的切片后,那么新的切片的大小和容量是多少呢?
这里有个公式,对于底层数组容量是 k 的切片 slice[i:j] 来说:

长度: j-i
容量: k-i

numbers := []int{0,1,2,3,4,5,6,7,8}
number3 := numbers[2:5]
printSlice(number3)
结果为:
len=3 cap=7 slice=[2 3 4]
capacity 为 7 是因为 number3 的 ptr 指向第三个元素, 
后面还剩 2,3,4,5,6,7,8, 所以 cap=7。

range简单用法:
1.

func main(){
    nums := []int{1,2,3,4};
    length := 0;
    for range nums {                                                  
        length++;
    }
    fmt.Println( length);
}
func main(){
   nums := []int{1,2,3,4}
   //会返回索引和值
   for i,num := range nums {
      fmt.Printf("索引是%d,长度是%d\n",i, num)
   }
}
//返回方法有哪些参数,不需要使用索引所以用_
func main() {
    fmt.Println(len(os.Args))
    for _, arg := range os.Args {
        fmt.Println(arg)
    }
}

你可能感兴趣的:(GO基础学习)