03 | 字符串,时间,流程控制,函数
一、strings和strconv的使用
strings
判断字符串s是否以prefix开头
strings.HasPrefix(s string,preffix string) bool:
判断字符串s是否以suffix结尾
stirngs.HasSuffix(s string,suffix string) bool:
判断str在s中首次出现的位置,如果没有出现,则返回-1
strings.Index(s string,str string) int:
判断str在s中最后出现的位置,如果没有出现,则返回-1
strings.LastIndex(s string,str string) int:
字符串替换
strings.Replace(str string,old string,new string,n int):
字符串计数
strings.Count(str string,count int)string:
重复count次str
strings.Repeat(str string,count int) string:
转换为小写
strings.ToLower(str string)
转换为大写
strings.ToUpper(str string)string:
去掉字符串首位空白字符
strings.TrimSpace(str string):
去掉字符串首尾cut字符
strings.Trim(str string,cut string):
去掉字符串首部cut字符
strings.TrimLeft(str string,cut string):
去掉字符串尾部cut字符
strings.TrimRight(str string,cunt string):
返回str空格分隔的所有子串的slice
strings.Field(str string):
返回str split分割的所有子串的slice
string.Split(str string,split string):
用sep把s1中的所有元素连接起来
strings.Join(s1 []string,sep string):
小练习 1
判断url 不是http://开头 机上http://s 判断是否以 / 结尾,不是加上
package main import ( "fmt" "strings" ) func urlProcess(url string) string { result := strings.HasPrefix(url, "http://") if !result { url = fmt.Sprintf("http://%s", url) } return url } func pathProcess(path string) string { result := strings.HasSuffix(path, "/") if !result { path = fmt.Sprintf("%s/", path) } return path } func main() { var ( url string path string ) fmt.Scanf("%s%s", &url, &path) url = urlProcess(url) path = pathProcess(path) fmt.Println(url) fmt.Println(path) }
输出结果如下

小练习 2
package main import ( "fmt" "strconv" "strings" ) func main() { str := " hello world abc \n" result := strings.Replace(str, "world", "you", 1) fmt.Println("replace:", result) count := strings.Count(str, "l") fmt.Println("count:", count) result = strings.Repeat(str, 3) fmt.Println("repeat:", result) result = strings.ToLower(str) fmt.Println("lower:", result) result = strings.ToUpper(str) fmt.Println("upper:", result) result = strings.TrimSpace(str) fmt.Println("trimSpace:", result) result = strings.Trim(str, " \n\r") fmt.Println("trim:", result) result = strings.TrimLeft(str, " \n\r") fmt.Println("trimLeft:", result) result = strings.TrimRight(str, " \n\r") fmt.Println("trimRight", result) splitResult := strings.Fields(str) for i := 0; i < len(splitResult); i++ { fmt.Println(splitResult[i]) } splitResult = strings.Split(str, "l") for i := 0; i < len(splitResult); i++ { fmt.Println(splitResult[i]) } str2 := strings.Join(splitResult, "l") fmt.Println("join:", str2) str2 = strconv.Itoa(1000) fmt.Println("itoa:", str2) number, err := strconv.Atoi("abc") if err != nil { fmt.Println("can not convert to int,", err) return } fmt.Println("number:", number) }
strconv
把一个整数转换成字符串
scronv.Itoa(i int):
把一个字符串转换成整数
scronv.Atio(str string)(int,errror):
二、Go中时间和日期
获取当前时间:now:= time.Now()
time.Now().Day() 返回时间点t对应那一月的第几日
time.Now().Minute() 返回t对应的那一小时的第几分种,范围[0, 59]。
time.Now().Month() String返回月份
time.Now().Year() 返回时间点t对应的年份。
time.Duration 用来表示纳秒
一些常用的时间常量
const (
Nanosecond Duration = 1
Microsecond =1000 * Nanosecond
Millisecond =1000 * Microsecond
Second =1000 * Millisecond
Minute =60 * Second
Hour =60 * Minute
)
小案例
写一个程序,获取当前时间,并格式化成 2017/06/15 08:05:00形式 ,统计一段代码的执行耗时,单位精确到微秒
package main
import (
"fmt"
"time"
)
func test() {
time.Sleep(time.Millisecond * 100)
}
func main() {
now := time.Now()
fmt.Println(now.Format("2006/01/02 15:04:05"))
start := time.Now().UnixNano()
test()
end := time.Now().UnixNano()
fmt.Printf("cost:%d us\n", (end-start)/1000)
}
输出结果如下

三 指针类型
普通的类型,变量存的就是值,也叫值类型
获取变量的地址,用& 比如: var a int, 获取a的地址:&a
指针类型,变量存的是一个地址,这个地址存的才是真正的值
获取指针类型所指向的值,用*,例如:var *p int, 使用 *p获取p指向值
小案例 1
package main
import "fmt"
func main() {
var a int = 10
fmt.Println(&a)
var p *int
p = &a
fmt.Println(*p)
*p = 100
fmt.Println(a)
}
输出结果如下

小案例 2
package main
import "fmt"
func modify(p *int) {
fmt.Println(p)
*p = 1000900
return
}
func main() {
var a int = 10
fmt.Println(&a)
var p *int
p = &a
fmt.Println("the address of p:", &p)
fmt.Println("the value of p:", p)
fmt.Println("the value of p point to variable:", *p)
fmt.Println(*p)
*p = 100
fmt.Println(a)
var b int = 999
p = &b
*p = 5
fmt.Println(a)
fmt.Println(b)
modify(&a)
fmt.Println(a)
}
输出结果如下

四、流程控制
if else 分支判断
常见格式类型如下:
if 条件{
}
if 条件{
}else{
}
if 条件{
}else if 条件{
}else{
}
switch case
语法格式:
switch var {
case var1:
case var2:
case var3:
default:
}
如果满足了var1 想要穿透下一个需要添加fallthrough
例子如下:
package main
import "fmt"
func main() {
var a int = 0
switch a {
case 0:
fmt.Println("a 等于0")
fallthrough
case 1:
fmt.Println("a等于1")
default:
fmt.Println("a等于默认值")
}
}
如果我们没有添加fallthrough只会打印a等于0,但是现在回把case1中的打印内容也打印出来
同样这里我们需要知道case 后面是可以写条件的
输出结果如下

for语句
语法
for 初始化变量;条件判断;变量修改{
}
例子 1
for i:=0;i<100;i++{
fmt.Println(i)
}
例子 2
package main
import "fmt"
func Print(n int) {
for i := 1; i < n+1; i++ {
for j := 0; j < i; j++ {
fmt.Printf("A")
}
fmt.Println()
}
}
func main() {
Print(6)
}
输出结果如下

for循环的其他几种常见写法
for 条件 {
}
死循环的写法
for {
}
for range语句
通过一个例子理解:
package main
import "fmt"
func main() {
str := "hello 世界"
for index, val := range str {
fmt.Printf("index[%d] val[%c] len[%d]\n", index, val, len([]byte(string(val))))
}
}
这里需要注意的一个问题是,range str返回的是两个值,一个是字符串的下标,一个是字符串中单个的字符
输出结果如下

goto 和label语句
package main import "fmt" func main() { LABEL1:for i:=0;i<5;i++{ for j:=0;j<i;j++{ if j == 2{ continue LABEL1 } fmt.Printf("i is :%d and j is:%d\n",i,j) } } }
代码中我们在continue 后面添加了一个LABEL1这样当循环匹配到j等于4的时候,就会跳出循环,重新回到最外成i的循环,而如果没有LABEL1则就会跳出j的本次循环,执行j++进入到j的下次循环
输出结果如下

我们接着看goto的用法,但是代码中我们不建议使用goto
package main
import "fmt"
func main() {
i :=0
HEAR:
fmt.Println(i)
i++
if i == 5{
return
}
goto HEAR
}
输出结果如下

break 和continue
一句话解释:break是终止整个循环,continue是终止此次循环
五、函数详解
声明语法
func 函数名 (参数列表) [(返回列表)]{
}
一些常见的写法例子
func add(){
}
func add(a int,b int){
}
func add(a int,b int) int {
}
func add(a int,b int) (int,int) {
}
func add(a,b int)(int,int){
}
go函数的特点
- 不支持重载,一个包不能包含两个名字一样的函数
- 函数是一等公民,函数也是一种类型,一个函数可以赋值给变量
- 匿名函数
- 多返回值
其他几个概念可能都好理解,我们这里主要说说第二条,函数也是一种类型,一个函数可以赋值给变量
通过下面的例子演示
package main
import "fmt"
type add_func func(int,int) int
func add(a,b int) int {
return a+b
}
func operator(op add_func,a int,b int) int {
return op(a,b)
}
func main() {
c := add
fmt.Println(c)
sum := operator(c,100,200)
fmt.Println(sum)
}
这里通过type自定义了一个add_func类型
输出结果如下

函数参数传递方式
这里主要有两种方式:值传递,引用传递
无论是值传递还是引用传递,传递给函数的都是变量的副本,不过值传递的是值的拷贝,引用传递传递的是地址的拷贝,一般来说,地址拷贝更为高效,而值拷贝取决于拷贝的对象的大小,对象越大,则性能越低
命名返回值的名字
通过下面的例子理解:
package main
func add_sum(a,b int)(c int){
c = a + b
return
}
func main() {
println(add_sum(10,20))
}
在这里返回值c因为在返回值的列表中已经声明了,所以在函数中不用声明,直接return,默认返回的是c
输出结果如下

下划线标识符,用来忽略返回值
func main() {
sum, _ := calc(100, 200)
}
可变参数
表示0个或多个参数
fucn add(arg...int) int{
}
package main
import "fmt"
//接受0个或多个参数
func add(arg...int) int {
var sum int =0
for i := 0; i < len(arg); i++ {
sum += arg[i]
}
return sum
}
func main() {
//sum := add(10, 3, 3, 3, 3)
sum := add()
fmt.Println(sum)
}
输出结果如下

表示1个或多个参数
func add(a int,arg...int) int {
}
其中arg是一个slice,我们可以通过arg[index]获取指定位置的参数
通过len(arg)可以判断参数的个数
package main
import "fmt"
func add(a int, arg ...int) int {
var sum int = a
for i := 0; i < len(arg); i++ {
sum += arg[i]
}
return sum
}
func concat(a string, arg ...string) (result string) {
result = a
for i := 0; i < len(arg); i++ {
result += arg[i]
}
return
}
func main() {
sum := add(10, 3, 3, 3, 3)
fmt.Println(sum)
res := concat("hello", " ", "world")
fmt.Println(res)
}
输出结果如下

defer用途
-
当函数返回时,执行defer语句,可以用来做资源清理
-
多个defer语句,按先进后出的方式执行
-
defer语句中变量,在defer声明时就决定了
1. 关闭文件句柄
func read() {
file := open(filename)
defer file.Close()
//文件操作
}
2 锁资源释放
func read() {
mc.Lock()
defer mc.Unlock()
//其他操作
}
3 数据库连接释放
func read() {
conn := openDatabase()
defer conn.Close()
//其他操作
}
通过下面的例子理解:
package main
import "fmt"
func main() {
a:=0
defer fmt.Println("defer---->",a)
a++
fmt.Println(a)
}
结果会在最后打印defer---->0 ,这里就体现了defer语句中变量,在defer声明时就决定了
package main import "fmt" var ( result = func(a1 int, b1 int) int { return a1 + b1 } ) func test(a, b int) int { result := func(a1 int, b1 int) int { return a1 + b1 } return result(a, b) } func main() { fmt.Println(result(100, 200)) var i int = 0 defer fmt.Println(i) defer fmt.Println("second") i = 10 fmt.Println(i) }
输出结果如下

小案例
1 编写程序,在终端输出九九乘法表
package main
import "fmt"
func multi() {
for i := 0; i < 9; i++ {
for j := 0; j <= i; j++ {
fmt.Printf("%d*%d=%d\t", (i + 1), j+1, (i+1)*(j+1))
}
fmt.Println()
}
}
func main() {
multi()
}
输出结果如下

2. 一个数如果恰好等于它的因子之和,这个数就称为“完数”。例如6=1+2+3.
编程找出1000以内的所有完数。
package main
import "fmt"
func perfect(n int) bool {
var sum int = 0
for i := 1; i < n; i++ {
if n%i == 0 {
sum += i
}
}
return n == sum
}
func process(n int) {
for i := 1; i < n+1; i++ {
if perfect(i) {
fmt.Println(i)
}
}
}
func main() {
var n int
fmt.Scanf("%d", &n)
process(n)
}
输出结果如下

3. 输入一个字符串,判断其是否为回文。回文字符串是指从左到右读和从右到
左读完全相同的字符串。
package main
import "fmt"
func process(str string) bool {
t := []rune(str)
length := len(t)
for i, _ := range t {
if i == length/2 {
break
}
last := length - i - 1
if t[i] != t[last] {
return false
}
}
return true
}
// 输入一个字符串判断是否为回文
func main() {
var str string
fmt.Scanf("%sd", &str)
if process(str) {
fmt.Println("yes")
} else {
fmt.Println("no")
}
}
输出结果如下

4.输入一行字符,分别统计出其中英文字母、空格、数字和其它字符的个数。
package main
import (
"bufio"
"fmt"
"os"
)
func count(str string) (worldCount, spaceCount, numberCount, otherCount int) {
t := []rune(str)
for _, v := range t {
switch {
case v >= 'a' && v <= 'z':
fallthrough # 如果是小写字母,执行下一行
case v >= 'A' && v <= 'Z':
worldCount++
case v == ' ':
spaceCount++
case v >= '0' && v <= '9':
numberCount++
default:
otherCount++
}
}
return
}
func main() {
reader := bufio.NewReader(os.Stdin)
result, _, err := reader.ReadLine()
if err != nil {
fmt.Println("read from console err:", err)
return
}
wc, sc, nc, oc := count(string(result))
fmt.Printf("wolrd count:%d\n space count:%d\n number count:%d\n others count:%d\n", wc, sc, nc, oc)
}
输出结果如下

5. 计算两个大数相加的和,这两个大数会超过int64的表示范围.
package main import ( "bufio" "fmt" "os" "strings" ) func multi(str1, str2 string) (result string) { if len(str1) == 0 && len(str2) == 0 { result = "0" return } var index1 = len(str1) - 1 var index2 = len(str2) - 1 var left int for index1 >= 0 && index2 >= 0 { c1 := str1[index1] - '0' c2 := str2[index2] - '0' sum := int(c1) + int(c2) + left if sum >= 10 { left = 1 } else { left = 0 } c3 := (sum % 10) + '0' result = fmt.Sprintf("%c%s", c3, result) index1-- index2-- } for index1 >= 0 { c1 := str1[index1] - '0' sum := int(c1) + left if sum >= 10 { left = 1 } else { left = 0 } c3 := (sum % 10) + '0' result = fmt.Sprintf("%c%s", c3, result) index1-- } for index2 >= 0 { c1 := str2[index2] - '0' sum := int(c1) + left if sum >= 10 { left = 1 } else { left = 0 } c3 := (sum % 10) + '0' result = fmt.Sprintf("%c%s", c3, result) index2-- } if left == 1 { result = fmt.Sprintf("1%s", result) } return } func main() { reader := bufio.NewReader(os.Stdin) result, _, err := reader.ReadLine() if err != nil { fmt.Println("read from console err:", err) return } strSlice := strings.Split(string(result), "+") if len(strSlice) != 2 { fmt.Println("please input a+b") return } strNumber1 := strings.TrimSpace(strSlice[0]) strNumber2 := strings.TrimSpace(strSlice[1]) fmt.Println(multi(strNumber1, strNumber2)) }
输出结果如下


浙公网安备 33010602011771号