Go语言-基础语法

Hello,GO!

package main // 定义包名
func main() {
	print("Hello,Go")
}

main函数要点

  • ++无参数、无返回值++
  • main方法必须要在main包里面
  • go run main.go就可以执行
  • 如果文件不叫main.go,则需要go build 之后再 go run

package声明-包声明

  • 语法形式:package xxx
  • 字母和下划线的组合
  • ++可以和文件夹不同名字++
  • 同一个文件夹下的声明一致
  • 引入包语法形式:import [alias] xxx
  • 如果包引入了但是没有使用,会报错
  • 匿名引入:前面多一个下划线

基本类型

String

  • 双引号括起来String,"转义
  • 反引号括起来大段文字(需要换行的),里面双引号不用转义了
    goland会帮忙转义好
  • len()计算字节长度
    len("你好")//=6
    计算长度:utf8.RuneCountInString("你好")//为2
  • strings主要方法:查找和替换;大小写转换;子字符串相关;相等

rune类型

rune类型直观理解就是:字符
rune不是byte
rune本质是int32,一个rune四个字节
go当中没有char只有rune
rune不是数字,也不是char,也不是 byte !
(但实际中不太常用)

bool,int,unit.float

  • bool: true,false
  • int8,int16,int32,int54,++int++
  • unit8,unit16,unit32,unit64,++unit++(无符号数)
  • float32,float64

byte类型

++byte,字节,本质上是unit8++
对应的操作包在bytes上

类型总结

  • golang的数字类型明确标注了长度、有无符号数
  • golang不会帮你做类型转换。类型不同无法通过编译。也因此,++string只能和string拼接在一起++
  • golang有一个很特殊的rune类型,接近一般语言的char或者character的概念,++非面试情况下,可以理解为“rune=字符”++
  • string遇事不决找strings包

变量声明

变量声明var

  • var,语法:var name type=value
  • 全局变量还是包变量是由首字母大小写决定的
    如:
    var Global="全局变量" //Global首字母大写,全局可以访问
    var local="包变量" //首字母小写,只能在这个包里面使用,子包也不能用
var (                  //块声明
    First string ="abc"
    second int32 = 16
)

golang是强类型语言,类型不一致==判定不等

变量声明 :=

  • 只能用于局部变量,即方法内部
  • golang使用类型推断来推断类型。数字会被理解为int或者float64。(所以其他类型的数字,就得用var来声明
func main(){
    a:=13
    println(a)
    b:="你好"
    println(b)
}

变量声明易错点

  • 变量声明了没有使用:与import一样,没有使用的话编译不会通过
  • 类型不匹配
  • 同作用域下,变量只能声明一次

常量声明const

  • 首字母是否大写控制了访问性:大写包
  • 驼峰命名
  • 支持类型推断
  • 无法修改值
const internal = "包内可访问"
const External = "包外可访问"

方法声明

四个部分:

  • 关键字func
  • 方法名:首字母是否大写决定了作用域
  • 参数列表[]
  • 返回列表[]

Go支持多返回值
多返回值,参数有名字,但返回值没有:

func Fun1(a string, b int) (int, string){
    return 0,"你好"
}

返回值具有名字,可以在内部直接复制,然后返回,也可以忽略age,name直接返回别的:

func Fun2(a string, b int) (age int, name string){
    age=19
    name="Tom" <
    return
}

单返回值

func Fun0(a string) string{
    return "Hello, "+name
}

不定参数-切片(后面讲)
_,d :=Fun2(a:"a",b:"b")
下划线_为匿名

  • golang支持多返回值,这是一个很大的不同点
  • golang方法的作用域和变量作用域一样,通过大小写控制
  • golang的返回值是可以有名字的,可以通过给予名字让调用方清楚知道你返回的是什么

最简单的web服务器

package main // 定义包名
import (
	"fmt"
	"log"
	"net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hi there, Ilove %s!", r.URL.Path[1:])
}
func main() {
	http.HandleFunc("/", handler)
	log.Fatal(http.ListenAndServe(":8088", nil))
}

增加几个路由

func home(w http.ResponseWriter, r *http.Request){
    fmt.Fprintf(w,"这是主页")
}

func user(w http.ResponseWriter, r *http.Request){
    fmt.Fprintf(w,"这是用户")
}

func main(){
    http.HandleFunc("/",home)
    http.HandleFunc("/user",user)
    log.Fatal(http.ListenAndServe(":8088", nil))
}

fmt格式化输出

返回字符串的API
str:=fmt.Sprintf("hello,I am %s",name)
直接输出
fmt.Printf("hello,i am %s",name)

占位符:

  • %s字符串 %d整型
  • %v 值的默认格式。当打印结构体时,“加号”标记(%+v)会添加字段名
  • %#v 相应值的Go语法表示
  • %T 相应值的类型的Go语法表示
  • %% 字母上的百分号,并非值的占位符
package main
 
import (
	"fmt"
)
 
type Sample struct {
	a   int
	str string
}
 
func main() {
	s := Sample{a: 1, str: "hello"}
 
	fmt.Printf("%v\n", s)   //{1, hello}
	fmt.Printf("%+v\n", s)  //{a:1, str:hello}
	fmt.Printf("%#v\n", s)  //main.Sample{a:1, str:"hello"}
	fmt.Printf("%T\n", s)   // main.Sample
	fmt.Printf("%%\n", s.a) // %  %!(EXTRA int=1)
}

数组和切片

数组和别的语言的数组差不多,语法是:[cap]type

  1. 初始化要指定长度(容量)
  2. 直接初始化
  3. arr[i]的形式访问元素
  4. len和cap操作用于获取数组长度
package main // 定义包名
import "fmt"

func main() {
	//直接初始化一个三个元素的数组。大括号里面多一个或者少一个都编译不通过
	a1 := [3]int{9, 8, 7}
	fmt.Printf("a1: %v, len: %d, cap: %d\n", a1, len(a1), cap(a1))

	//初始化一个三个元素的数组,所有元素都是0
	var a2 [3]int
	fmt.Printf("a2: %v, len: %d,cap: %d\n", a2, len(a2), cap(a2))

	//a1=append(a1,a2) 数组不支持append操作

	//按下标索引
	fmt.Printf("a1[1]:%d", a1[1])
	//超出下标范围,直接崩溃,编译不通过
	//fmt.Printf("a1[99]: %d",a1[99])
}

结果如下:

a1: [9 8 7], len: 3, cap: 3
a2: [0 0 0], len: 3,cap: 3
a1[1]:8 

切片,语法:[]type

  1. 直接初始化
  2. make初始化:make([]type, length, capacity)
  3. arr[i]的形式访问元素
  4. append追加元素
  5. len获取元素数量
  6. cap获取切片容量
  7. 推荐写法:s1 :=make([]type,0,capacity)
package main 
import "fmt"

func main() {
	s1 := []int{1, 2, 3, 4} //直接初始化了4个元素的切片
	fmt.Printf("s1: %v, len: %d, cap: %d\n", s1, len(s1), cap(s1))
	s2 := make([]int, 3, 4) //创建了一个包含三个元素,容量为4的切片
	fmt.Printf("s2: %v, len: %d, cap: %d\n", s2, len(s2), cap(s2))
	s2 = append(s2, 7) //后边添加一个元素,没有超出容量限制,不会发生扩容
	fmt.Printf("s2: %v, len: %d, cap: %d\n", s2, len(s2), cap(s2))
	s2 = append(s2, 8) //后边添加一个元素,触发扩容
	fmt.Printf("s2: %v, len: %d, cap: %d\n", s2, len(s2), cap(s2))
	s3 := make([]int, 4) //只传入一个参数,表示创建一个含有四个元素,容量也为四个元素的
	fmt.Printf("s3: %v, len: %d, cap: %d\n", s3, len(s3), cap(s3))
	//按下标索引
	fmt.Printf("s3[2]: %d", s3[2])
	//超出下标范围,直接崩溃
	//runtime error: index out of range[99] with length 4
	//fmt.Printf("s2[99]:%d",s3[99])
}

结果如下:

s1: [1 2 3 4], len: 4, cap: 4
s2: [0 0 0], len: 3, cap: 4    
s2: [0 0 0 7], len: 4, cap: 4  
s2: [0 0 0 7 8], len: 5, cap: 8
s3: [0 0 0 0], len: 4, cap: 4  
s3[2]: 0   
数组切片
直接初始化支持支持
make不支持支持
访问元素arr[i]arr[i]
len长度已有元素个数
cap长度容量
append不支持支持
是否可以扩容不可以可以

用切片基本不会出错

子切片

数组和切片都可以通过[start:end]的形式来获取子切片:

  1. arr[start:end],获得[start,end)之间的元素
  2. arr[:end],获得[0,end)之间的元素
  3. arr[start:],获得[start,len(arr)]之间的元素
    左闭右开原则

如何理解切片
最直观的对比:ArrayList,即基于数组的List的实现,切片的底层也是数组
跟ArrayList的区别:

  1. 切片操作是有限的,不支持随机增删(即没有add,delete方法,需要自己写代码)
  2. 只有append操作
  3. 切片支持子切片操作,和原本切片是共享底层数组

共享底层(optional)

核心:共享数组
子切片和切片究竟会不会互相影响,就抓住一点:它们是不是还共享数组?
就是如果它们结构没有变化,那肯定是共享的;但是结构变化了,就可能不是共享了

package main

import "fmt"

func ShareSlice() {
	s1 := []int{1, 2, 3, 4}
	s2 := s1[2:]
	fmt.Printf("s1: %v,len: %d,cap: %d\n", s1, len(s1), cap(s1))
	fmt.Printf("s2: %v,len: %d,cap: %d\n", s2, len(s2), cap(s2))

	s2[0] = 99
	fmt.Printf("s1: %v,len: %d,cap: %d\n", s1, len(s1), cap(s1))
	fmt.Printf("s2: %v,len: %d,cap: %d\n", s2, len(s2), cap(s2))

	s2 = append(s2, 199)
	fmt.Printf("s1: %v,len: %d,cap: %d\n", s1, len(s1), cap(s1))
	fmt.Printf("s2: %v,len: %d,cap: %d\n", s2, len(s2), cap(s2))

	s2[1] = 1999
	fmt.Printf("s1: %v,len: %d,cap: %d\n", s1, len(s1), cap(s1))
	fmt.Printf("s2: %v,len: %d,cap: %d\n", s2, len(s2), cap(s2))
}
func main() {
	ShareSlice()
}

结果如下:

s1: [1 2 3 4],len: 4,cap: 4
s2: [3 4],len: 2,cap: 2        
s1: [1 2 99 4],len: 4,cap: 4   
s2: [99 4],len: 2,cap: 2       
s1: [1 2 99 4],len: 4,cap: 4   
s2: [99 4 199],len: 3,cap: 4   
s1: [1 2 99 4],len: 4,cap: 4   
s2: [99 1999 199],len: 3,cap: 4

for

for和别的语法差不多,有三种形式:

  1. for{},类似while的无限循环
func ForLoop() {
	arr := []int{9, 8, 7, 6}
	index := 0
	for {
		if index == 3 {
			break
		}
		fmt.Printf("%d=>%d,", index, arr[index])
		index++
	}
	fmt.Printf("for loop end\n")
}
  1. fori,一般的按照下标循环
func ForI() {
	arr := []int{9, 8, 7, 6}
	for i := 0; i < len(arr); i++ {
		fmt.Printf("%d=>%d,", i, arr[i])
	}
	fmt.Printf("for i loop end\n")
}
  1. for range最为特殊的range遍历
func ForR() {
	arr := []int{9, 8, 7, 6}
	//如果只是需要value,可以用_代替index
	//如果只需要index也可以去掉写成for index:=range arr
	for index, value := range arr {
		fmt.Printf("%d=>%d,", index, value)
	}
	fmt.Printf("for r loop end")
}
  1. break和continue和别的语言一样

if-else

if-else和别的语言差不多
if condition{…}
else if condition{…}
else{…}
带局部变量声明的if-else:

func IfUsingNewVariable(start int, end int) {
	if distance := end - start; distance > 100 {
		fmt.Printf("距离太远:%d\n", distance)
	} else {
		// else分支也可以没有
		fmt.Printf("距离不远:%d\n",distance)
	}
	//这里不能访问distance
}
  1. distance只能在if块,或者后面所有的else块里面使用
  2. 脱离了if-else块,则不能再使用

switch

switch和别的语言差不多
switch后面可以是基础类型的字符串,或者满足特定条件的结构体
最大差别:不用加break了!

func ChooseFruit(fruit string) {
	switch fruit {
	case "苹果":
		fmt.Println("这是一个苹果")
	case "草莓", "蓝莓":
		fmt.Println("这是莓果")
	default:
		fmt.Printf("新水果:%s\n", fruit)
	}
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值