Java 太卷了转 GO(一)

GO 的一些基础用法,帮助 Java 程序员快速转 GO。

变量的声明

  1. 第一种,指定变量类型,声明后若不赋值,使用默认值0。
var a int
var a int = 10
  1. 根据值自行判定变量类型。
var a = 10
  1. 第三种,省略var, 注意 :=左侧的变量不应该是已经声明过的,否则会导致编译错误。
a := 10

常量

const b int = 10
const b = 10

枚举

常量可以用作枚举

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

iota

它简化了常量用于增长数字的定义

const (
    CategoryBooks = iota // 0
    CategoryHealth       // 1
    CategoryClothing     // 2
)

函数

package main

import "fmt"

func main() {

	var a int = 10
	var b int = 20

	fmt.Println("1--", a, b)

	swap(a, b)
	fmt.Println("2--", a, b)
}

func swap(a int, b int) {
	var c int = a
	a = b
	b = c
}

main 函数

main 函数只能出现在 package main 中。是程序的入口。

init 函数

init 函数可在package main中,可在其他package中,可在同一个package中出现多次。

执行顺序

golang里面有两个保留的函数:init函数(能够应用于所有的package)和main函数(只能应用于package main)。这两个函数在定义时不能有任何的参数和返回值。

go程序会自动调用init()和main(),所以你不需要在任何地方调用这两个函数。每个package中的init函数都是可选的,但package main就必须包含一个main函数。

如果main包还导入了其它的包,那么就会在编译时将它们依次导入。有时一个包会被多个包同时导入,那么它只会被导入一次(例如很多包可能都会用到fmt包,但它只会被导入一次,因为没有必要导入多次)。

当一个包被导入时,如果该包还导入了其它的包,那么会先将其它包导入进来,然后再对这些包中的包级常量和变量进行初始化,接着执行init函数(如果有的话),依次类推。

值传递

值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。

默认情况下,Go 语言使用的是值传递,即在调用过程中不会影响到实际参数。

swap 函数就是值传递的,交换两个数的操作,但是不会生效。

引用传递(指针传递)

&: 取地址
*: 解引用

package main

import "fmt"

func main() {

	var a int = 10
	var b int = 20

	fmt.Println("1--", a, b)

	swap2(&a, &b)
	fmt.Println("2--", a, b)
}

func swap2(a *int, b *int) {
	var c = *a
	*a = *b
	*b = c
}

defer

defer 相当于 java 中 finally

数组

var variable_name [SIZE] variable_type

var nums [10]int;

如果数组长度不确定,可以使用 ... 代替数组的长度

balance := [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

切片

var identifier []type
未指定大小的数组来定义切片,切片不需要说明长度。

var slice1 []type = make([]type, len)

// 也可以简写为

slice1 := make([]type, len)

// 直接初始化
s :=[] int {1,2,3 }

// 直接初始化切片,[]表示是切片类型,{1,2,3}初始化值依次是1,2,3.其cap=len=3

len()长度,
cap()容量,当长度等于容量时扩容为当前长度的2倍。

append 和 copy 函数

append 用于向切片中追加一个元素,

package main


import "fmt"


func main() {
   var numbers []int
   printSlice(numbers)


   /* 允许追加空切片 */
   numbers = append(numbers, 0)
   printSlice(numbers)


   /* 向切片添加一个元素 */
   numbers = append(numbers, 1)
   printSlice(numbers)


   /* 同时添加多个元素 */
   numbers = append(numbers, 2,3,4)
   printSlice(numbers)


   /* 创建切片 numbers1 是之前切片的两倍容量*/
   numbers1 := make([]int, len(numbers), (cap(numbers))*2)


   /* 拷贝 numbers 的内容到 numbers1 */
   copy(numbers1,numbers)
   printSlice(numbers1)   
}


func printSlice(x []int){
   fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}

map

Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。

Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。

/* 声明变量,默认 map 是 nil */
var map_variable map[key_data_type]value_data_type

/* 使用 make 函数 */
map_variable := make(map[key_data_type]value_data_type)

结构体

package main

import "fmt"

// 类名大写,其他包也可以引用到。小写就不行
type Books struct {
	title  string
	author string
}

// 普通函数,参数是结构体
func printBook(book Books) {
	fmt.Printf("book = %v\n", book)
}

// 普通函数,参数是结构体,值传递,修改不会在 main 函数中生效
func SetTitle(book Books) {
	book.title = "Python"
}
// 使用指针传递参数可以修改其属性值
func SetTitle2(book *Books) {
	book.title = "Python"
}

// 这个函数相当于结构体的函数,可以 book.SetAuthor() 调用。
// 注意是个指针传递,可以写成值传递,但修改没有效果
func (t *Books) SetAuthor() {
	t.author = "lisi"
}

func main() {
	book := Books{"GO", "test"}
	fmt.Println(book)
	book.title = "C"
	fmt.Println(book)

	java := Books{title: "Java", author: "22"}
	printBook(java)
	SetTitle(java)
	printBook(java)

	SetTitle2(&java)
	java.SetAuthor()
	printBook(java)
}

继承

method

method 附属在一个给定类型上,语法和函数的语法几乎一样,只是在 func 后面增加了一个 receiver(也就是 method 所依从的主体)

method 给用户定义的类型添加新的行为。

method 的接收者可以是普通类型,也可以是指针类型,是普通类型的时候接收的值的副本,也就是值传递,是指针类型的时候接收的是内存地址,就是引用传递。

func (r receiverType) funcName(parameters) (results)

虽然 method 的名字一模一样,但是如果接收者不一样,那么 method 就不一样

method 继承

如果匿名字段实现了一个 method,那么包含这个匿名字段的 struct 也能调用该 method

package main

import (
	"fmt"
)

type Human struct {
	name string
	sex  string
}

func (t *Human) Eat() {
	fmt.Println("eat")
}

func (t *Human) Walk() {
	fmt.Println("walk")
}

type SuperHuman struct {
	// 匿名字段,使得 SuperHuman 的对象也拥有 Human 的 method
	Human
	level int
}

// 重写 SuperHuman 的 Walk 方法。
func (t *SuperHuman) Walk() {
	fmt.Println("fly")
}

func main() {
	man := Human{
		name: "zhangsan",
		sex:  "男",
	}
	man.Eat()
	man.Walk()

	// 创建子类对象
	//superMan := SuperHuman{
	//	Human{"lisi", "男"}, 100,
	//}
	var superMan SuperHuman
	superMan.level = 100
	superMan.name = "lisi"
	superMan.sex = "男"

	superMan.Eat()
	superMan.Walk()
}

interface

interface 本质上是个指针。
interface 定义了一组 method,如果某个对象实现了某个接口的所有方法,则此对象就实现了这个接口

interface 是一组抽象方法的集合,必须由其他非 interface 类型实现,而不能自我实现,

package main

import "fmt"

// 定义一个 interface,有两个方法 eat、run
type Anaimal interface {
	eat()
	run()
}

// ======
// 定义子类,实现 interface 中的 2个方法,必须要完全实现 interface 中的所有方法,才算是继承
type Dog struct {
}

func (dog Dog) eat() {
	fmt.Println("dog eat")
}

func (dog Dog) run() {
	fmt.Println("dog run")
}

// ======

type Cat struct {
}

func (cat Cat) eat() {
	fmt.Println("cat eat")
}

func (cat Cat) run() {
	fmt.Println("cat run")
}

// ======

func main() {
	var anaimal Anaimal
	anaimal = new(Dog)
	anaimal.eat()
	anaimal.run()

	anaimal = new(Cat)
	anaimal.eat()
	anaimal.run()
}

以上这些就是 GO 的一些基础知识。学会了这些下面就能简单进行开发了。

下一篇文章介绍下 GO 的框架,ORM 框架,Web 框架,以及用这些开发一个小应用。


参考网站
https://learnku.com/go/wikis
https://learnku.com/docs/the-little-go-book
https://learnku.com/docs/the-way-to-go
https://www.yuque.com/aceld/mo95lb/dsk886
https://www.runoob.com/go/go-map.html

2022/09/07 15:00 下午 posted in  GO