Go基础篇

栏目: Java · 发布时间: 5年前

内容简介:&符号的意思是对变量取地址,如:变量a的地址是&a

判断和流程控制

https://www.jianshu.com/p/77be2afa225d

  1. if的使用,布尔判断条件不加括号;而且初始化的时候可以添加一个申明的初始值
if num == 3 {
            fmt.Println("index 3 :", i)
 }else{
     fmt.Println(num)
 }
  1. switch 的使用:默认每个case自带break,如果想继续判断需要手动添加 fallthrough;有2种写法(直接switch 或者 switch i),适用不同的业务场景;case的值可以是整数,字符串等类型
//这种场景适用 条件值是固定的业务场景
    i := 5
    switch i{
        case 1:
            fmt.Println("i is equal to 1")
        case 2:
            fmt.Println("i is equal to 2")
        case 3,4,5,6:
            fmt.Println("i is equal to 3,4,5 or 6")
            fallthrough
        default:
            fmt.Println("others")
    }

    //这种场景适用 条件值不固定,为某一区间的业务场景
    switch {
        case i < 0:
            fmt.Println("小于零")
        case i > 0:
            fmt.Println("大于零")
        default:
            fmt.Println("等于零")
    }
  1. for循环:go的for循环有如下三种形式。条件不需要括号。for循环 数组和map的时候可以结合range一起用
for init; condition; post{} //和C的for一样
for condition{}             //和while一样
for{}  //结合break,continue

nums := []int{2, 3, 4}
for i, num := range nums {
        if num == 3 {
            fmt.Println("index 3 :", i)
        }else{
             fmt.Println(num)
        }
    }

Golang的函数特征

  1. Go的函数支持多返回值,这方便编程,java实现多返回值只能封装在实体对象或者Hashmap中,典型的使用场景就是分页查询,既需要知道count,也需要当页的数据
func main(){
 result1,result2 := swap("hello", "kitty")
}

func swap(x, y string) (string, string) {
   return y, x
}
  1. Go的函数写法和其它语言不一样,先申明变量的名字,再申明变量的类型。设计者觉得这样才符合正常人类的思维方式

  2. Go函数和通过方法名的大小写来实现对外权限的控制

  3. Go函数不支持重载

  4. Go语言的函数的参数支持不指定数量和类型

func main(){
    result := sum(3,5,7,9)
    fmt.Println("结果为:", result)
}

func sum(aregs ...int) int {
    s := 0
    for _, number := range aregs{
        s += number
    }
    return s
}

Go对象的申明

  1. 申明一个对象,不需要再写冗余的get、set方法、机械式的构造函数、toString方法了,自带灵活的构造函数
  2. 支持三种类型的构造函数
  3. 另外通过(r *rect)来添加类的方法
type Books struct {
   title string
   author string
   subject string
   book_id int
}

func main() {
   var Book1 Books 
   Book1.title = "Go 语言"
   Book1.author = "www.runoob.com"
   Book1.subject = "Go 语言教程"
   Book1.book_id = 6495407
   fmt.Printf( "Book title : %s\n", book1.title);

    var Book2 Books=Books{"Go 语言", "www.runoob.com", "Go 语言教程", 6495407}
    fmt.Println(Book2)
    fmt.Println(Book2.title)

    Book4 :=Books{
        title:"testJson",
        subject:"testSubject",
    }
}

type rect struct {
    width int
    height int
}
 
func (r *rect) area() int {
    return r.width * r.height
}
 
func main() {
    r := rect{width: 10, height: 5}
    fmt.Println("area: ", r.area())
}

Go对象的继承和多态

  1. Go语言通过把目标对象当作自身成员变量的方式,间接的实现继承
func main(){
    stu := Student{"chain"}
    fmt.Println(stu)

    aStu := AStudent{Student{"chain"}, 23}
    fmt.Println(aStu)
}

type Student struct{
    name string
}

type AStudent struct{
    Student
    Age int
}
  1. Go语言通过实现接口的方式,来实现多态,需要用到指针 &,不能指定为非 Phone接口的实现类,否则会报错

    Go语言简洁归简洁,有时候过于简洁并不方便,比如不能知道这个类的接口是哪个接口

定义一个Phone的接口,它的实现类必须实现call()方法
type Phone interface {
    call()
}

定义一个普通类NokiaPhone 
type NokiaPhone struct {
}

实现call()的方法
func (nokiaPhone NokiaPhone) call() {
    fmt.Println("I am Nokia, I can call you!")
}

type IPhone struct {
}

func (iPhone IPhone) call() {
    fmt.Println("I am IPhone, I can call you!")
}

func main() {
    var phone Phone
    phone = &NokiaPhone{}
    phone.call()
    phone= &IPhone{}
    phone.call()
}

Go中指针的使用 & 、 *

https://www.cnblogs.com/grimm/p/5623860.html

&符号的意思是对变量取地址,如:变量a的地址是&a

符号的意思是对指针取值,如: &a,就是a变量所在地址的值,当然也就是a的值了

和 & 可以互相抵消,同时注意, &可以抵消掉,但&

是不可以抵消的

a和

&a是一样的,都是a的值,值为1 (因为*&互相抵消掉了)
var a int = 1
    var b *int = &a
    fmt.Println("a = ",a)  //1
    fmt.Println("&a = ",&a)//0xc00000a098 a的内存地址
    fmt.Println("*&a = ",*&a)//1    *和&抵消掉了,还是1
    fmt.Println("b = ",b) //0xc00000a098 b是a的指针,和 &a的值一样
    fmt.Println("&b = ",&b) //0xc000006028  指针的指针
    fmt.Println("*b = ",*b) //1 b指针指向的值

defer的用法

http://developer.51cto.com/art/201306/400489.htm

defer语句延迟执行一个函数,该函数被推迟到当包含它的程序返回时(包含它的函数 执行了return语句/运行到函数结尾自动返回/对应的goroutine panic/当前线程 runtime.Goexit())执行。

按照栈的形式后进先出的原则依次执行每个defer注册的函数。通常用来进行资源释放,错误的处理,清理数据等。

  1. defer是后进先出
//打印的顺序 main method 、method2、 method1,因为类似于栈模型,后进先出
func main() {
    defer doSomething("method 1")
    defer doSomething("method 2")
    fmt.Println("i am main method")
}
func doSomething(things string){
    fmt.Println(" ia am doing somthing",things)
}
  1. defer虽然是在当前方法执行后执行,但是defer的参数就会被实时解析。下面打印 1 0
func main() {
    i := 0
    defer fmt.Println(i) //此时是0
    i++
    defer fmt.Println(i) //此时是1
}
  1. 经典的使用场景:简化资源的释放,用起来有类似finally的效果,特别适合多分支返回语句的情况,可以明显简化代码
func main() {
    fmt.Println(judgeNumber(-1))
    fmt.Println(judgeNumber(0))
    fmt.Println(judgeNumber(1))
}

func judgeNumber(num int) string{
    var lockName ="numlock"
    getLock(lockName)
    defer unlock(lockName)
    switch  {
    case num<0 :
        return "nagetive"
    case num==0 :
        return "Zero"
    default:
        return "good number"
    }
}

func getLock(lockname string){
    fmt.Println("i got the lock of ",lockname)
}

func unlock(lockname string){
    fmt.Println("i release the lock of ",lockname)
}
  1. defer是 Go 语言中 异常处理的一部分,和panic()、recover()一起使用

错误和异常处理机制

https://www.jianshu.com/p/f30da01eea97

  • Golang中引入error接口类型作为错误处理的标准模式,如果函数要返回错误,则返回值类型列表中肯定包含error,可逐层返回,直到被处理。
  • Golang中引入两个内置函数panic和recover来触发和终止异常处理流程,同时引入关键字defer来延迟执行defer后面的函数。

异常和错误的正确使用方式:

  1. 当错误的类型只有1种的时候,直接用bool,而不是用error的实现类,因为bool更简洁
//当hostType为 virtual_machine 或者bare_metal时校验通过,否则校验失败
func (self *AgentContext) IsValidHostType(hostType string) bool {
    return hostType == "virtual_machine" || hostType == "bare_metal"
}
  1. 一般error的返回值放在返回值的最后一个

  2. 规范使用errors.New的使用,放在常量文件里面,标准化输出,而不是每次用的时候,自己定义输出内容

util.go 里面定义这样的常量
var ERR_NOT_EXIST = errors.New("file is not exist")

其它地方直接使用
    err := createResource1()
    if err != nil {
        return ERR_CREATE_RESOURCE1_FAILED
    }

经典的异常和错误的使用方式

  1. 手动抛出异常:
if f < 0 {
        return 0, errors.New("math: square root of negative number")
    }
  1. 手动实现一个特定类型的异常类(类似于 java 的自定义Exception),需要实现Error接口的Error()方法
// 定义一个 DivideZeroError 结构,分母为0的专门的异常处理类
type DivideError struct {
    dividee int
    divider int
}

// 实现 `error` 接口
func (de *DivideError) Error() string {
    strFormat := `
    Cannot proceed, the divider is zero.
    dividee: %d
    divider: 0
`
    return fmt.Sprintf(strFormat, de.dividee)
}

// 定义 `int` 类型除法运算的函数
func Divide(varDividee int, varDivider int) (result int, errorMsg string) {
    if varDivider == 0 {
        dData := DivideError{
            dividee: varDividee,
            divider: varDivider,
        }
        errorMsg = dData.Error()
        return
    } else {
        return varDividee / varDivider, ""
    }

}

func main() {

    // 正常情况
    if result, errorMsg := Divide(100, 10); errorMsg == "" {
        fmt.Println("100/10 = ", result)
    }
    // 当被除数为零的时候会返回错误信息
    if _, errorMsg := Divide(100, 0); errorMsg != "" {
        fmt.Println("errorMsg is: ", errorMsg)
    }

}
  1. 通过defer实现一个未知可能类型的异常,类似于java的 try catch finally的用法,联合 panic() recover()一起使用
func main(){
    defer func(){
        if err := recover(); err != nil{ //捕捉异常并处理
            fmt.Println("err: ", err)
        }}()

    if num, err := delive(20, -5); err == nil{
        fmt.Printf("%f / %f = %f\n", 20.0, -5.0, num)
    }else{
        fmt.Println(err)
    }

    if num, err := delive(20, 0); err == nil{
        fmt.Printf("%f / %f = %f\n", 20.0, 0.0, num)
    }else{
        fmt.Println(err)
    }

    fmt.Println("Test")
}

func delive(numA, numB float32) (float32, error){
    if numB < 0{
        return 0, errors.New("被除数不能为负数")
    }else if numB == 0{
        panic("被除数不能为0") //抛出异常
    }else{
        return numA/numB, nil
    }
}

Go的数据类型和转换

  1. int 默认是和CPU的位数一样的,在64位的操作系统上,默认int就是64位,相当于java的long型数据
    当然 int支持: int8 、int16、 int32、int64
  2. uint:无符号位的整形,就是没有符号位了,比如 int8 的范围是-127 到128,但是 uint8的范围是 0- 255
  3. 类型转换
var test string="120"
    //把test字符串转换为10进制的32位结果的数字
    result,err:=strconv.ParseInt(test,10,32)
    if err!=nil{
        fmt.Println(result)
    }

    count :=2000
    resultResult:= strconv.Itoa(count)

import原理

https://blog.csdn.net/zhangzhebjut/article/details/25564457

  1. 按照import的先后顺序挨个引入依赖类,并且先执行依赖类的init方法,再执行自己的init方法,最后执行main方法
  2. 现在的1.11的版本,import还是加 相对路径吧;或者把工程路径放在 GOPATH/src下面。
  3. 路径前面加 . 的话,则可用直接引用,省略引用包名前缀
  4. import的话,还支持别名操作,和 _ 初始化假引用
  5. package下小写开头的方法对外不可见,类似于java中的private
import (
    . "fmt"
    "./learn1"
    )

 import( f “fmt” )

Server版helloWord

设置访问端口为 8888

  1. 设置不接受参数的网络请求
func main() {
    http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
        fmt.Fprintln(writer,"<h1>hello kitty </h1>")
    })
    http.ListenAndServe(":8888",nil)
}
  1. 接收URL参数, 利用Fprintf使用格式化输出, %s为占位符,取的是 request中 参数name的值
http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
        fmt.Fprintf(writer,"<h1>hello kitty %s</h1>",request.FormValue("name"))
    })
  1. 并发型输出HelloWorld,1秒内开5000个微线程输出
func main() {
    for i :=0;i<5000;i++{
        go printHelloWorld(i)
    }
    time.Sleep(time.Second)
}

func printHelloWorld(i int){
    fmt.Printf("hello kitty ,%d \n",i)
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Cracking the Coding Interview

Cracking the Coding Interview

Gayle Laakmann McDowell / CareerCup / 2015-7-1 / USD 39.95

Cracking the Coding Interview, 6th Edition is here to help you through this process, teaching you what you need to know and enabling you to perform at your very best. I've coached and interviewed hund......一起来看看 《Cracking the Coding Interview》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具