发布时间:2019-09-11 07:45:00编辑:auto阅读(1680)
strings 包实现了用于操作字符串的简单函数。
strings.HasPrefix(s string, prefix string) bool
判断字符串s是否以prefix开头
strings.HasSuffix(s string, suffix string) bool
判断字符串s是否以suffix结尾
strings.Index(s string, str string) int
判断str在s中首次出现的位置,如果没有出现,则返回-1
strings.LastIndex(s string, str string) int
判断str在s中最后出现的位置,如果没有出现,则返回-1
strings.Replace(str string, old string, new string, n int) string
字符串替换,对原始字符串str进行替换,把原始的old替换成new。
最后一个n是替换的次数,如果 n<0
则替换所有。一般就-1。
strings.Count(str string, substr string) int
字符串计数,返回 substr 在 str 里出现的次数。
strings.Repeat(str string, count int) string
返回一个新的字符串,由 str 重复 count 次构成。或者这么讲,将 count 个字符串 str 连接成一个新的字符串。
strings.ToLower(str string) string
转为小写
strings.ToUpper(str string) string
转为大写
strings.TrimSpace(s string) string
去掉字符串首尾空白字符,空白字符除了空格至少还包括: “\n\t\r” 。
相当于下面的这个Trim方法的简写:
strings.Trim(s string, " \n\t\r") string
strings.Trim(s string, cutset string) string
去掉字符串首尾的 cutset 字符串里包含的字符
示例:
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Printf("[%q]", strings.Trim(" !!! Achtung! Achtung! !!! ", "! "))
}
// 上面的cutset包含2个字符: ! 和 空格,
// 所以会把字符串 s 两边的这两个字符都去掉,直到遇到这两个字符以外的字符为止
/* 运行结果:
H:\Go\src\go_dev\day3\strings>go run test_trim.go
["Achtung! Achtung"]
H:\Go\src\go_dev\day3\strings>
*/
如果只需要去掉前面的部分,或者只去掉末尾的部分,还有下面2个方法:
strings.TrimLeft(s string, cutset string) string
strings.TrimRight(s string, cutset string) string
strings.Split(s string, sep string) []string
返回 sep 分隔的所有字符串 s 的子串的slice
如果是用空格分隔的,那么可以用下面的 Fields 方法
strings.Fields(s string) []string
strings.Join(a []string, sep string) string
用 sep 把 a 里的所有元素拼接起来。是上面的Split的逆向操作
strconv 包提供了字符串和基本数据类型之间的转换操作。
strconv.Itoa(i int) string
整数转字符串
strconv.Atoi(s string) (i int, err error)
字符串转整数。注意,这个返回2个值。成功转换,返回整数,err为空(nil);如果s是空或者无效数字,就会有err,并且返回值是0。
time包提供显示和计算时间用的函数。
获取当前时间用 time.Now()
:
package main
import (
"fmt"
"time"
)
func main(){
now := time.Now()
fmt.Println(now)
fmt.Printf("%T\n", now)
}
/* 运行结果:
H:\Go\src\go_dev\day3\time>go run now.go
2018-10-07 12:51:52.9706623 +0800 CST m=+0.001999101
time.Time
H:\Go\src\go_dev\day3\time>
*/
这个数据类型是 time.Time
包括但不只有下面这些方法,全部的方法去官网查吧:
示例:
package main
import (
"fmt"
"time"
)
func main(){
now := time.Now()
fmt.Println(now.Year(), now.Month(), now.Day())
}
/* 运行结果
H:\Go\src\go_dev\day3\time>go run time_info.go
2018 October 7
H:\Go\src\go_dev\day3\time>
*/
用(Time) Format格式化
首先,默认提供这么多格式,都定义在time的常量里:
const (
ANSIC = "Mon Jan _2 15:04:05 2006"
UnixDate = "Mon Jan _2 15:04:05 MST 2006"
RubyDate = "Mon Jan 02 15:04:05 -0700 2006"
RFC822 = "02 Jan 06 15:04 MST"
RFC822Z = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone
RFC850 = "Monday, 02-Jan-06 15:04:05 MST"
RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST"
RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
RFC3339 = "2006-01-02×××5:04:05Z07:00"
RFC3339Nano = "2006-01-02×××5:04:05.999999999Z07:00"
Kitchen = "3:04PM"
// Handy time stamps.
Stamp = "Jan _2 15:04:05"
StampMilli = "Jan _2 15:04:05.000"
StampMicro = "Jan _2 15:04:05.000000"
StampNano = "Jan _2 15:04:05.000000000"
)
这些预定义的常量,其实使用的都是一个特定的时间。这个时间是Unix time 1136239445,因为MST是GMT-0700,所以这个指定的时间也可以看做:
01/02 03:04:05PM '06 -0700
选一个上面的常量字符串,或者自己根据这个特定时间照着写一个格式化字符串,调用Format方法进行格式化:
package main
import (
"fmt"
"time"
)
func main(){
now := time.Now()
fmt_now := now.Format(time.RFC1123Z)
fmt.Println(fmt_now)
fmt_str := "2006/1/2 15:04:05 Monday"
fmt.Println(now.Format(fmt_str))
fmt.Println(now.Format("01/02 03:04:05PM '06 -0700"))
}
/* 运行结果
H:\Go\src\go_dev\day3\time>go run format.go
Sun, 07 Oct 2018 13:39:27 +0800
2018/10/7 13:39:27 Sunday
10/07 01:39:27PM '18 +0800
H:\Go\src\go_dev\day3\time>
*/
用fmt.Printf格式化
package main
import (
"fmt"
"time"
)
func main(){
now := time.Now()
fmt.Printf(
"%02d/%02d/%02d %02d:%02d:%02d %v",
now.Year(),
now.Month(),
now.Day(),
now.Hour(),
now.Minute(),
now.Second(),
now.Weekday(),
)
}
time.Duration 类型代表两个时间点之间经过的纳秒数,可表示的最长时间段约为290年。
涉及到下面这些常量:
const (
Nanosecond Duration = 1
Microsecond = 1000 * Nanosecond
Millisecond = 1000 * Microsecond
Second = 1000 * Millisecond
Minute = 60 * Second
Hour = 60 * Minute
)
用time.Now()获取程序运行之前和运行之后的时间。然后用Sub方法计算出这2个时间之间间隔的时间(时间段),最后打印出来。
另外还有个方法,就是直接获取两个时间点的时间戳的纳秒数,然后相减得到的就是运行时间的纳秒数。
package main
import (
"fmt"
"time"
)
func test(){
var sum int
for i := 1; i <= 100; i++ {
sum += i
time.Sleep(2 * time.Nanosecond) // 每一步都计算后都加上2纳秒的延迟
}
fmt.Println(sum)
}
func main(){
t0 := time.Now()
test()
t1 := time.Now()
fmt.Printf("程序执行的时间是: %v\n", t1.Sub(t0))
t := t1.Sub(t0)
fmt.Println("换算成微秒", float64(t) / float64(time.Microsecond), "微秒")
// 另外一个方法
nt0 := time.Now().UnixNano() // 当前时间戳的纳秒数
test()
nt1 := time.Now().UnixNano()
fmt.Println("程序执行时间是:", nt1 - nt0, "纳秒")
}
/* 运行结果
H:\Go\src\go_dev\day3\time>go run sub_time.go
5050
程序执行的时间是: 148.3263ms
换算成微秒 148326.3 微秒
5050
程序执行时间是: 150043400 纳秒
H:\Go\src\go_dev\day3\time>
*/
做单位换算的时候,需要注意数据类型。
参与除法的两个数如果数据类型不同会报错。或者像 n / 1000
这样,n是变量一定是有类型的,1000的数据类型会根据n的类型做类型推导。
如果是int类型相除,得到的结果也是int类型。如果要保留小数,就要浮点类型,比如float64。不能对结果做类型转换(此时小数位已经丢失了),而是要对做参与除法的int类型做类型转换。
普通类型,变量存的就是值,也叫值类型。
获取变量的地址,用&。比如:var a int
,获取a的地址:&a
指针类型,变量存的是一个地址,这个地址存的才是值
获取指针类型所指向的值,用*。比如:var p *int
,获取p指向的值:*p
package main
import "fmt"
func main() {
var a int=5
fmt.Println("变量a的地址:", &a)
var p *int = &a // 定义指针类型p,p的值就是a的地址
fmt.Println("通过p拿到a的值:", *p) // 要获取p指向的值,用*p
*p = 100 // 通过*p修改值
fmt.Println("a现在的值是:", a) // 打印确认,上面改的就是a的值
}
/* 运行结果
H:\Go\src\go_dev\day3\pointer>go run check_pointer.go
变量a的地址: 0xc04204e058
通过p拿到a的值: 5
a现在的值是: 100
H:\Go\src\go_dev\day3\pointer>
*/
语法:
// 第一种
if condition1 {
}
// 第二种
if condition1 {
} else {
}
// 第三种
if condition 1 {
} else if condition2 {
} else if condition3 {
} else {
}
语法:
switch var1 {
case val1:
case val2:
case val3. val4 :
default:
}
go语言了,case结尾不需要加break,并且语句也不会继续匹配后面的条件。如果需要继续匹配之后的条件,可以添加fallthrough关键字
package main
import "fmt"
func main() {
fmt.Print("请输入:")
var choices int
fmt.Scanf("%d", &choices)
switch choices {
case 1:
fmt.Println("你的选择是一")
case 2:
fmt.Println("你的选择是二")
case 3, 4:
fmt.Println("你的选择是三或四")
default:
fmt.Println("没变对应的选择")
}
}
switch后面的表达式不是必需的。在此种情况下,整个switch结构与多个 if / else 的逻辑作用等同:
package main
import "fmt"
func main() {
fmt.Print("请输入分数(1-100):")
var score int
fmt.Scanf("%d", &score)
fmt.Println(score)
switch {
case score > 100:
fmt.Println("分数超出范围")
case score == 100:
fmt.Println("你的成绩是:A+满分")
case score > 90:
fmt.Println("你的成绩是: A")
case score > 80:
fmt.Println("你的成绩是:B")
case score > 70:
fmt.Println("你的成绩是:C")
case score > 60:
fmt.Println("你的成绩是:D")
case score > 0:
fmt.Println("你的成绩是:E")
default:
fmt.Println("0分或者输入无效")
}
}
猜数字,写一个程序,随机生成一个0到100的整数n。然后用户在终端输入数字,如果和n相等,则提示用户猜对了。如果不相等,则提示用户,大了还是小了。
package main
import (
"fmt"
"math/rand"
"time"
)
func create_num() int {
rand.Seed(time.Now().UnixNano())
return rand.Intn(101)
}
func main() {
n := create_num()
//fmt.Println(n)
var input int
var flag bool = false
// 循环结构还没讲,先用for写个死循环
for {
fmt.Print("请输入数字(0-100):")
fmt.Scanf("%d\n", &input)
switch {
case input == n:
fmt.Println("猜对了", n)
//break // case里不需要break,似乎也支持写break,不会报错
flag = true // 上面的break是switch里的break,无法跳出for循环。等switch结束后判断flag
case input > n:
fmt.Println("大了,再小点")
case input < n:
fmt.Println("小了,再大点")
}
if flag {
break // 这里是switch外面,这里的break是跳出for循环的
}
}
}
写法1
for 初始化语句; 条件判断; 变量修改 {
}
练习
写一个程序,在终端打印如下图形
A
AA
AAA
AAAA
AAAAA
下面有两个实现方法:
package main
import (
"fmt"
"strings"
)
// 自己的思路
func print1(tag string, n int) {
for i := 1; i <= n; i++ {
fmt.Println(strings.Repeat(tag, i))
}
}
// 讲师的例子,这段是学for循环,这个方法把for循环用的更透
func print2(tag string, n int) {
for i := 1; i <= n; i++ {
for j := 0; j < i; j++ {
fmt.Print(tag)
}
fmt.Println()
}
}
func main(){
print1("A", 5)
print2("B", 6)
}
写法2
for 条件 {
}
// 如果条件时true,就是个死循环
for true {
}
// 上面可以简写,省掉true
for {
}
写法3
for range 用来遍历数组、slice、map、chan
用下面的例子举例了,遍历后获得2个值,i是下标,v是值:
package main
import (
"fmt"
)
func main() {
s := "abcdefg" // 数组什么的还没学,不过字符串也能遍历
for i, v := range s {
// fmt.Println(i, v) // 遍历之后变成字符了
fmt.Println(i, string(v))
}
}
break: 跳出当前循环
continue :结束本次循环,进入下一次继续
for、switch 或 select 语句都可以配合标签(label)形式的标识符使用,即某一行第一个以冒号(:)结尾的单词(gofmt 会将后续代码自动移至下一行)。标签的名称是大小写敏感的,为了提升可读性,一般建议使用全部大写字母。
在多级嵌套语句中,非常有用。下面例子的continue后面指定了标签,这样就直接作为外层的for循环的continue操作:
package main
import "fmt"
func main() {
LABEL1:
for i := 0; i <= 5; i++ {
for j := 0; j <= 5; j++ {
if j == 4 {
continue LABEL1
}
fmt.Printf("i is: %d, and j is: %d\n", i, j)
}
}
}
break 标签的效果和 continue 是一样的,差别只是break和continue的动作。
下面是goto的示例:
package main
func main() {
i:=0
HERE:
print(i)
i++
if i==5 {
return
}
goto HERE
}
上面的这种是逆向的使用goto,使用标签和 goto 语句是不被鼓励的。而且总有更加可读的替代方案来实现相同的需求。
如果必须使用 goto ,应当只使用正序的标签(标签位于 goto 语句之后),但注意标签和 goto 语句之间不能出现定义新变量的语句,否则会导致编译失败。
声明语法:func 函数名 ([参数列表]) [(返回值列表)] {}
// 没有参数也没有返回值
func test() {
}
// 有参数,没有返回值
func test(a int, bint) {
}
// 有参数,有一个返回值
func test(a int, b int) int {
}
// 有参数,有多个返回值
func test(a int, b int) (int, int) {
}
// 可以省略前面的参数类型
fun test(a, b int) {
}
Golang函数的特点:
多返回值
函数赋值给变量使用的示例
package main
import "fmt"
// 函数也是一种类型,下面用type做一个类型定义
// type关键字,什么要做定义
// add_func,定义的名字是add_func
// func,函数也是一种类型,所以要定义的类型是函数
// 后面是这个函数类型的参数类型和返回值类型
type add_func func(int, int) int
// 写一个函数,函数的类型和上面的自定义类型一样
func add(a, b int) int {
return a + b
}
// 再写一个减法的吧
func sub(a, b int) int {
return a - b
}
// 在写一个函数,第一个参数是函数类型
// 后面的参数是要用来给参数1的函数进行计算的
func operator(op add_func, a, b int) int {
return op(a, b)
}
// 主函数
func main() {
// 第一个变量add,是一个函数
sum := operator(add, 10, 20)
fmt.Println(sum)
var (
c add_func
res int
)
// 函数也可以赋值给变量
c = add
res = operator(c, 110, 40)
fmt.Println(res)
c = sub
// 这次调用方法不变,但是变量c变量,换了一个函数进行计算
res = operator(c, 110, 40)
fmt.Println(res)
}
## 参数传递的方式
函数参数传递的方式下面2种:
+ 值传递:各种基本数据类型
+ 引用传递:map、slice(切片)、chan(管道)、指针、interface
**注意:**无论是值传递还是引用传递,传递给函数的都是变量的副本。不过,值传递是值的拷贝,引用传递是地址的拷贝。一般来说,地址拷贝更为高效。而值拷贝取决于拷贝的对象的大小,对象越大,则性能越低。
## 命名返回值的名字
也可以在声明函数的时候给返回值命名:
```go
func add (a, b int) (c int) {
c = a + b // 这里变量c不用声明,可以直接使用
return // 直接return就好了,也不用说明要返回什么
}
多返回值的函数中,更加方法:
func calc (a, b int) (sum int, avg int) {
sum = a + b
avg = sum / 2
return
}
使用下划线(_),可以忽略不使用的返回值:
func calc (a, b int) (sum int, avg int) {
sum = a + b
avg = sum / 2
return
}
func main() {
sum, _ := calc(10, 20)
}
在参数类型前加3个点,可以把参数定义为可变参数:
// 0个或多个参数
func sum(arg ...int) int {
}
// 1个或多个参数
func sum(a int, arg ...int) int {
}
// 2个或多个参数
func sum(a int, b int, c ...int) int {
}
变量 arg 是一个 slice (切片)。可以理解为数组,通过 arg[index] 访问所有参数,通过 len(arg) 来判断传递参数的个数
使用可变参数求和,可以传1个或多个int参数:
package main
import "fmt"
func sum(a int, arg ...int) (res int) {
res = a
for i := 0; i < len(arg); i++ {
res += arg[i]
}
return
}
func main() {
var res int
res = sum(1)
fmt.Println(res)
res = sum(1, 2)
fmt.Println(res)
res = sum(1, 2, 3)
fmt.Println(res)
}
当函数返回时,会执行defer语句。因此,可以用来做资源清理
多个defer语句,按先进后出的方式执行
defer语句中的变量的值,在defer声明时就决定了
举例说明:
package main
import "fmt"
func main() {
var i int = 1
// 下面这句并不立刻执行,而是等函数返回时再执行
// 但是函数的参数的值,在此时就已经决定了,也就是i=1
defer fmt.Println(i)
i = 22
fmt.Println(i)
}
/* 执行结果
H:\Go\src\go_dev\day3\function>go run defer_demo.go
22
1
H:\Go\src\go_dev\day3\function>
*/
用途
以关闭文件句柄举例:
func read () {
file := open(filename) // 打开了一个文件
defer file.Close() // 紧接着用defer关闭这个文件
// 之后再写各种文件操作
// 到文件返回时,defer就会执行,关闭这个文件句柄
}
使用defer不踩坑
函数返回的过程是这样子的:先给返回值赋值,然后调用defer表达式,最后才是返回到调用函数中。
defer表达式可能会在设置函数返回值之后,在返回到调用函数之前,修改返回值,使最终的函数返回值与你想象的不一致。
一、编写程序,在终端输出九九乘法表
二、一个数如果恰好等于他的因子只和,那么这个数就称为“完数”。例如6=1+2+3。编程找出1000以内的所有完数。
三、输入一个字符串,判断其是否为回文。回文字符串是指从左到右读和从右到左读完全相同的字符串。
四、输入一行字符,分别统计出其中英文字母、空格、数字和其它字符的个数。
五、计算两个大数相加的和,这两个大数会超过int64的表示范围。
上一篇: 3.IT-解决方案-3-Backup-S
下一篇: Python学习笔记__12.11章 H
47848
46403
37291
34738
29321
25977
24923
19955
19549
18033
5798°
6421°
5936°
5965°
7071°
5920°
5950°
6446°
6408°
7787°