go语言基本语法

Go语言

一、特点

1、函数式编程   闭包

2、工程化   资源管理,错误处理,测试文档,

3、并发编程   goroutine和channel  调度器。

4、接口编程, interface

5、全新的静态类型开发语言

6、更丰富的内置类型slice

7、错误处理:

defer, panic和recover

二、语法

Package声明:表示go代码所属的包。建立一个名字为main的包,在该包中包含一个叫做main()的函数。无参,也没有定义返回值。

声明以后是import语句,引入需要的模块。

需要使println()函数所以引入的是fmt

函数定义使用func开头。

所有Go函数(包括在对象编程中会提到的类型成员函数)以关键字func开头。一个常规的 函数定义包含以下部分: func 函数名(参数列表)(返回值列表) { // 函数体 } 对应的一个实例如下: func
Compute(value1 int, value2 float64)(result float64, err error) { // 函数体 } Go支持多个返回值。以上的示例函数Compute()返回了两个值,一个叫result,另一个是 err。并不是所有返回值都必须赋值。在函数返回时没有被明确赋值的返回值都会被设置为默认
值,比如result会被设为0.0,err会被设为nil。

三、定义变量

package main

import "fmt"

var(

a=3

b=4

c=2

d=true

)

func variableZeroValue(){

var a int

var s
string

fmt.Printf("%d %q\n", a, s)

}

func 
variableInitialValue()  {

var a, b int = 3, 4

var s string = "abc"

fmt.Println(a, b, s)

}

func variableDecouments(){

var a, b,
c, d = 1, 3, true, "def"

fmt.Println(a,b,c,d)

}

func 
variableShorters()  {

a, b, c ,d := true, 0, 3, 5

fmt.Println(a, b, c, d)

}

func main()  {

fmt.Println("hello world")

variableZeroValue()

variableInitialValue()

variableDecouments()

variableShorters()

fmt.Println(a, b, c, d)

}

:= 只能在函数内使用

四、内建变量类型

1、bool,string

2、(u)int无符号整数,不加u是有符号整数。

Int32,int16,int8,int64,uintptr指针

3、byets,rune字符型

4、浮点型float32,float64,complex64, complex128负数

cmplx.Pow(math.E, 1i * math.Pi)+1

5、类型转换是强制的

func euler(){

   fmt.Println(cmplx.Pow(math.E, 1i * math.Pi)+1)
   c := 3 + 4i
   fmt.Println(cmplx.Abs(c))
}

五、常量

1、普通的定义

func consts(){
   const filename = "abc"
   const a, b = 3, 4
   fmt.Println(filename, a, b)
}

定义在函数内和函数外是一样的,都可以定义

2、枚举定义

普通类型就是自己定义

Iota是自增类型

func enums(){
   const (cpp  = iota
   python
   golang
   javascript)
   fmt.Println(cpp, python, golang, javascript)
}

六、条件语句

1、if

package main

import (
   "fmt"
   "io/ioutil"
)

//func main()  {
// const filename  = "abc.txt"
// contents, err := ioutil.ReadFile(filename)
// if err != nil{
//    fmt.Println(err)
// }else {
//    fmt.Println("%s\n", contents)
// }
//}
func main()  {
   const filename  = "abc.txt"
   if contents, err := ioutil.ReadFile(filename); err == nil{
      fmt.Println(string(contents))
   }else {
      fmt.Println("cannot print file contents", err)
      
   }

}

直接父类加

2、switch

func grade(source int) string{
   g := ""
   switch  {
   case source < 0 || source > 100:
      panic(fmt.Sprintf("wrong score: %d", source))
   case source < 60:
      g = "f"
   case source < 80:
      g = "c"
   case source < 900:
      g = "b"
   case source <= 100:
      g = "a"
   }
   return g
}

panic异常捕获语句

switch不需要break,自动有的break

3、for循环

func sums(){
   sum := 0
   for i := 1; i <=100; i++{
      sum += i
   }
   fmt.Println(sum)
}

for 什么不加的话就是死循环,不用的是while

七、函数

func div(a, b int)(q, r int){
   return a / b, a % b
}

函数名(参数,参数类型)(返回值,返回值类型)

可变参数只有一个就是..int

函数作为参数

八、指针

只有值传递一种方式。

*a ,*b,指针

&a,&b取地址

第一种实现

func swap(a, b *int)  {
   *a, *b = *b, *a
}
a, b := 2, 4
swap(&a, &b)
fmt.Println(a, b)

第二种实现方式:

func swaps(a, b int) (int, int) {
   return b, a
}

九、数组

package main

import "fmt"

func main(){
   var arr1 [5] int
   arr2 := [3]int{1, 3 ,5}
   arr3 := [...]int{2, 4, 6, 8, 10}
   var grid[4][5] int
   fmt.Println(arr1, arr2, arr3, grid)
   for i, value := range arr3{
      fmt.Println(i, value)
   }
}

定义了必须使用,要不然就使用_忽略变量

利用range。

意义明显。

数组是值类型,值类型会进行相应的拷贝文件

package main

import "fmt"
func printarray(arr [5]int){
   for i, v := range arr{
      fmt.Println(i, v)
   }

}
func main(){
   var arr1 [5] int
   arr2 := [3]int{1, 3 ,5}
   arr3 := [...]int{2, 4, 6, 8, 10}
   var grid[4][5] int
   fmt.Println(arr1, arr2, arr3, grid)
   //for i, value := range arr3{
      //fmt.Println(i, value)
   //}
   printarray(arr3)
   }

var arr[5] int 指定的是数组的长度和值得类型

数组作为函数的参数穿进去的时候就会拷贝数组

一般不会直接使用数组

十、切片slice

package main

import "fmt"

func main()  {
   arr := [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}
   s := arr[2:6]
   s1 := s[3:5]
   fmt.Println(s)
   fmt.Println(s1)
}

s1 因为知道其索引脚标,所以能够取出所在的值。因为其知道s的值,向后拓展只要不是超过s的长度即可

可以进行append,进行写入相关数据。

十一、Map

Map[k]v,map[k1]map[k2]v

创建make ,map    m2 := make(map[string]int)      m := map[string]string

遍历

查找值

删除

Map的key:map使用的是哈希表,必须可以比较相等。

除了slice,map,function的内建类型都可以作为key,

Struct类型不包括上述字段,也可以作为key

package main

import "fmt"

func main()  {
   m := map[string]string{    //no1
      "name":"mouse",
      "course":"golang",
      "site":"imocc",
      "quality":"notbad",
   }
   m2 := make(map[string]int)   // no2   == empty map
   var m3 map[string]int      //no3   == nil
   fmt.Println(m, m2, m3)
   for k := range m{       //遍历
      fmt.Println(k)

   }
   for k,v := range m{     //遍历
      fmt.Println(k,v)
   }
   courname := m["course"]     //索引查找,通过k查找v。如果不存在则是显示flase
   fmt.Println(courname)
   name, ok := m["course"]
   fmt.Println(name, ok)
   delete(m, "name")     //删除元素
   fmt.Println(m)
   }

十二、字符串

package main

func lengthSubstr(s string) int{
   last0curred := make(map[byte]int)
   start := 0
   maxlength := 0
   for i, ch := range []byte(s){
      if last0curred[ch] < start{
         start = last0curred[ch] + 1

      }
      if i - start + 1 > maxlength{
         maxlength = i - start +1
      }
      last0curred[ch] = i
   }
   return maxlength
}

func main() {
   lengthSubstr()
}
 

 
Strings.map等操作
 

 
 

十三、类

只是支持封装,不支持继承和多态。

没有class 只有struct

Type point struct {i,j,int}

package main

import "fmt"

type treeNode struct {
   value int
   left, right * treeNode
}

func createNode(value int) *treeNode{
   return &treeNode{value:value}
}

func main()  {
   var root treeNode
   root = treeNode{value:3}
   root.left = &treeNode{
   }
   root.right = &treeNode{5, nil, nil}
   root.right.left = new(treeNode)
   root.left.right = createNode(2)

   nodes := []treeNode{
      {value:3},
      {},
      {6, nil, &root},
   }
   fmt.Println(nodes)
}

结构创建在堆上还是栈上呢。

利用指针接收

十四、封装

名字一般使用camelcase

首字母大写public

首字母小写 private

十五、扩展已有类型

包:每个目录里面一个包

Main包包含可执行入口

为结构定义的方法必须放在同一个包内

可以是不同的文件。

Go语言没有继承:

如何扩充已有类型和别人的类型。

(1)定义别名

package queue

import "fmt"

type Queue []int

func (q *Queue) Push(v int){
   *q = append(*q, v)
}

func (q *Queue) Pop() int {
   head := (*q)[0]
   *q = (*q)[1:]
   return head
}

func main(){
   q := queue.Queue{1}

   q.Push(2)
   q.Push(3)
   fmt.Println(q.Pop())
   fmt.Println(q.Pop())
   fmt.Println(q.IsEmpty())
   fmt.Println(q.Pop())
   fmt.Println(q.IsEmpty())
}

(2)使用组合

十六、Gopath环境

不用的包不能导入,否则就会报错的

十七、接口

1、duck typing

2、Go语言中的duck typing

假的retriever
package mock

type Retriever struct {      //定义retriever类
   Contents string
}

func (r Retriever) Get(url string) string{
   return r.Contents
}

really接口

package real

import (
   "net/http"
   "net/http/httputil"
   "time"
)

type Retriever struct {
   UserAgent string
   TimeOut time.Duration
}
func (r Retriever) Get(url string) string{
   resp, err := http.Get(url)
   if err != nil{
      panic(err)
   }
   result, err := httputil.DumpResponse(resp, true)
   resp.Body.Close()

   if err != nil{
      panic(err)
   }
   return string(result)
   }
package main

import ("fmt"
   "go-projects/retriever/mock"
)

type Retriever interface {     //定义了接口
   Get(url string) string     //定义了方法而已
}

func download(r Retriever) string {  //接口作为参数传入,然后调用定义 的Get函数
   return r.Get("www.123.com")
}
func main()  {
   var r Retriever
   r = mock.Retriever{"this is imock"}
   fmt.Println(download(r))

}

3、接口定义:

接口是隐士的,只是实现里面的方法啊而已

Interface  里面有两个东西一个是值,一个是类型,真实的值copyde,也可以是指针的。

4、接口的组合:

type RetrieverPoster interface {
   Retriever
   Poster
}

是许多小接口的组合,把许多小接口放在一起

传值的时候传retriever,都是具备的,r只是具备单一的

5、go语言标准的接口

Stringer:

Writer

十八、函数式编程

函数式编程

函数指针   高阶函数,函数到闭包

正统函数式编程:

1、不可变性:不能有状态,只有常量和函数

2、函数只能有一个参数。

package main

import "fmt"

func adder() func(int) int{
   sum := 0
   return func(v int) int {
      sum += v
      return sum
   }
   }

func main() {
   a := adder()
   for i := 0; i < 10; i++{
      fmt.Println(a(i))
   }
}

正统式函数编程:

type iAdder func(int)(int, iAdder) 

func adder2(base int) iAdder {
   return func(v int) (int, iAdder) {
      return base + v, adder2(base + v)
   }
}
func main() {
a1 := adder2(0)
for i := 0; i < 10; i++{
   var s int
   s, a1 = a1(i)
   fmt.Printf("0 + 1 + ... + %d = %d\n", i, s)
}
}

Go语言中也有匿名函数,没有名字的。

十九、异常处理

1、defer调用

package main

import "fmt"

func tryDefer()  {
   defer fmt.Println(1)
   fmt.Println(2)
   fmt.Println(3)

}
func main() {
   tryDefer()
}

添加defer之后不受return 和panic的影响

Go语言是因为栈的,先进后出的。

实现斐波那契数列,必须注意的是函数名字的大写

package fib

func Fibonacci() func() int{
   a, b := 0, 1
   return func() int {
      a, b = b, a + b
      return a
   }
}
package main

import (
   "bufio"
   "fmt"
   "os"
   "go-projects/functional/fib"
)

func tryDefer()  {
   defer fmt.Println(1)
   fmt.Println(2)
   fmt.Println(3)

}
func writeFile(filename string){
   file, err := os.Create(filename)
   if err != nil{
      panic(err)
   }
   defer file.Close()

   writer := bufio.NewWriter(file)
   defer writer.Flush()

   f := fib.Fibonacci()
   for i := 0; i<20; i ++{
      fmt.Fprintln(writer, f())
   }
}
func main() {
   tryDefer()
   writeFile("abc.txt")
}

何时调用 defer

在open/close

Lock/unlock

Printhead/printfooter

错误处理的概念:

func writeFile(filename string){
   //file, err := os.Create(filename)
   file, err := os.OpenFile(filename, os.O_EXCL|os.O_CREATE, 0666)
   if err != nil{
      if pathError, ok := err.(*os.PathError); !ok{
         panic(err)
      }else {
         fmt.Println("%s, %s, %s\n",
            pathError.Op,
            pathError.Path,
            pathError.Err)
      }
      return
      }
   defer file.Close()

   writer := bufio.NewWriter(file)
   defer writer.Flush()

   f := fib.Fibonacci()
   for i := 0; i<20; i ++{
      fmt.Fprintln(writer, f())
   }
}
func main() {
   tryDefer()
   writeFile("abc.txt")
}

自己创建error的类型

err = errors.New("this is a custom error")

统一的错误处理逻辑:

2、服务器内部的错误资源处理流程,统一的处理

package main

import (
   "io/ioutil"
   "net/http"
   "os"
)

func main() {
   http.HandleFunc("/list/",
      func(writer http.ResponseWriter, request *http.Request) {
         path := request.URL.Path[len("/list/"):]
         file, err := os.Open(path)
         if err != nil{
            panic(err)
         }
         defer file.Close()
         all, err := ioutil.ReadAll(file)
         if err != nil{
            panic(err)
         }
         writer.Write(all)
         })
   err := http.ListenAndServe(":888", nil)
   if err != nil{
      panic(err)
   }
}

一个简单的网页 程序。

直接给前端页面返回的是程序的错误代码

http.Error(writer,
   err.Error(),
http.StatusInternalServerError)

os.isempty   如果是空的话

使用主函数处理函数内部逻辑,外部进行一场的捕获即处理例如Python的装饰器的形式

func main() {
   http.HandleFunc("/list/",
      errWrapper(filelisting.Handlefilelist))

   err := http.ListenAndServe(":8888", nil)
   if err != nil{
      panic(err)
   }
}

panic和recover的区别:

1、panic

停止当前函数执行

一直向上返回,执行每一层的defer

如果没有recover,程序退出。

2、recover

仅在defer调用中使用

获取panic的值

如果无法获取,可重新panic

工作流程如下:

panic(errors.New("this is an error"))自己可以创建的异常的值和类型。
 
package main

import (
   "errors"
   "fmt"
)

func tryRecover()  {
   defer func() {
      r := recover()
      if err, ok := r.(error); ok{
         fmt.Println("Error occurred", err)
      }else {
         panic(r)
      }
   }()
   panic(errors.New("this is an error"))
}
 
 
尽量少用panic。
 
意料之内的使用error, 文件打不开
 
意料之外的使用panic, 数组超届
 
错误综合处理方法:

 
 

原文地址:https://www.cnblogs.com/wangchunli-blogs/p/9951245.html

时间: 2024-11-08 23:02:41

go语言基本语法的相关文章

C语言基本语法

C语言基本语法 #include <reg52.h>          //包含文件 #include <stdio.h> void main(void)                //主函数 { SCON=0x52; TMOD=0x20; TH1=0xf3; TR1=1;                        //此行及以上 3 行为PRINTF 函数所必须 printf("Hello I am KEIL. \n");               

嵌入式linux C++语言(二)——C++对C语言基础语法的扩展

嵌入式linux C++语言(二)--C++对C语言基础语法的扩展 C++是基于C语言扩展发展而来的面向对象的程序设计语言,本文将主要讨论C++语言基于C语言扩展的方面. 一.类型增强 1.类型检查更严格 在C语言中: const int a = 100; int *p = &a; 在C++语言中: const int a = 100;//必须在定义的时候初始化 const int *p = &a; 在C++语言中不能隐式转换数据类型. error: invalid conversion

Java语言基本语法

Java语言基本语法 一.标识符和关键字 标识符 在java语言中,用来标志类名.对象名.变量名.方法名.类型名.数组名.包名的有效字符序列,称为“标识符”: 标识符由字母.数字.下划线.美元符号组成,且第一个字符不能是数字: java语言区分大小写: 标志符命名规则:类名首字母大写,变量名和方法名采用驼峰标志法,常量全大写,多个单词之间用“_”隔开,包名全小写: 关键字 在java语言中,有一些专门的词汇已经被赋予了特殊的含义,不能再使用这些词汇来命名标识符,这些专有词汇,称为“关键字”: j

201671010139 2016-2017-2 JAVA 和C语言的语法区别

java和c语言的语法上有很多相似的地方,但也有很多不同. 一,在初始值的区别 在C语言中,是可以不初始化使用的 而在JAVA中,是必须初始化值的 二,在抽象方法或抽象类的区别 C语言的对等语法是"纯虚函数"和"抽象类" Java使用abstract关键字修饰抽象方法或抽象类,final类不能被继承 都使用抽象类作为继承层次中的基类,提供一般概念,由子类实现其抽象方法,且抽象类都不能被直接实例化为对象 E.super关键字的区别 JAVA super关键字,指代父类

Go 语言基础语法

Go 语言基础语法 上一章节我们已经了解了 Go 语言的基本组成结构,本章节我们将学习 Go 语言的基础语法. Go 标记 Go 程序可以由多个标记组成,可以是关键字,标识符,常量,字符串,符号.如以下 GO 语句由 6 个标记组成: fmt.Println("Hello, World!") 6 个标记是(每行一个): 1. fmt 2. . 3. Println 4. ( 5. "Hello, World!" 6. ) 行分隔符 在 Go 程序中,一行代表一个语句

黑马程序员 ---- C 语言基础语法

C 语言基础语法 C程序是由函数组成. C程序的入口是一个名字叫做 main 的函数,简称main函数. 不管程序中有多少函数,都是先执行main函数. 1 #include <stdio.h> 2 3 int main(void) 4 5 { 6 7 return 0; 8 9 } 1.编写 2.编译 cc -c 文件名.c 生成 .o 文件 3.链接 cc 文件名.o      // 2.3结合在一起:  cc 文件名.c -o 文件名 4.运行 ./a.out // ./文件名 C语言中

黑马程序员------C 语言学习笔记---C语言基本语法成分

黑马程序员------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! ------- 1.1     C语言基本语法成分 #include <stdio.h> int main() { #define PI 3.14 int r; double s; double m; // 提示用户输入半径 pri

C语言之语法

1. #if defined #endif #if defined ( POWER_SAVING ) osal_pwrmgr_device( PWRMGR_BATTERY ); #endif #if (**) {语句##:} #endif 如果(**)为真,也就是逻辑1,的话就编译下面的语句.如果(**)不为真.则不编译下面的语句. 2. #ifndef #define #endif 头件的中的#ifndef,这是一个很关键的东西.比如你有两个C文件,这两个C文件都include了同一个头文件.

C++语言学习(二)——C++对C语言基础语法的扩展

C++语言学习(二)--C++对C语言基础语法的扩展 C++是基于C语言扩展发展而来的面向对象的程序设计语言,本文将主要讨论C++语言基于C语言扩展的方面. 一.实用性增强 C语言中变量的定义必须在作用域开始的位置进行定义. #include <stdio.h> int main(int argc, char *argv[]) { int i;//定义变量 int j; //使用变量 for(i = 0; i < 10; i++) { for(j = 0; j < 10; j++)

Groovy语言学习--语法基础(5)

至此groovy语言学习-语法基础就结束了,新的工作已经安排下来,要干活了. 对groovy了解到一定程度之后就可以在java项目中对其进行引入了.为此新建了一个微型的项目,个人觉得千言万语不如代码实现来得实在.程序员应该用代码来沟通,文字只是解释. 到此,感觉算是对groovy完成了入门练习.内部涉及的实现复杂和性能优化,超出目前学习能力范围,后续随着技能的提升可能还会去进一步研究.先到此为止了. 相关代码见项目:https://github.com/islowcity/groovy 项目中有