内容简介:strings 包实现了用于操作字符串的简单函数。判断字符串s是否以prefix开头判断字符串s是否以suffix结尾
strings 包
strings 包实现了用于操作字符串的简单函数。
HasPrefix
strings.HasPrefix(s string, prefix string) bool
判断字符串s是否以prefix开头
HasSuffix
strings.HasSuffix(s string, suffix string) bool
判断字符串s是否以suffix结尾
Index
strings.Index(s string, str string) int
判断str在s中首次出现的位置,如果没有出现,则返回-1
LastIndex
strings.LastIndex(s string, str string) int
判断str在s中最后出现的位置,如果没有出现,则返回-1
Replace
strings.Replace(str string, old string, new string, n int) string
字符串替换,对原始字符串str进行替换,把原始的old替换成new。
最后一个n是替换的次数,如果 n<0
则替换所有。一般就-1。
Count
strings.Count(str string, substr string) int
字符串计数,返回 substr 在 str 里出现的次数。
Repeat
strings.Repeat(str string, count int) string
返回一个新的字符串,由 str 重复 count 次构成。或者这么讲,将 count 个字符串 str 连接成一个新的字符串。
ToLower
strings.ToLower(str string) string
转为小写
ToUpper
strings.ToUpper(str string) string
转为大写
TrimSpace
strings.TrimSpace(s string) string
去掉字符串首尾空白字符,空白字符除了空格至少还包括: “\n\t\r” 。
相当于下面的这个Trim方法的简写:
strings.Trim(s string, " \n\t\r") string
Trim
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
Split
strings.Split(s string, sep string) []string
返回 sep 分隔的所有字符串 s 的子串的slice
如果是用空格分隔的,那么可以用下面的 Fields 方法
strings.Fields(s string) []string
Join
strings.Join(a []string, sep string) string
用 sep 把 a 里的所有元素拼接起来。是上面的Split的逆向操作
strconv 包
strconv 包提供了字符串和基本数据类型之间的转换操作。
Itoa
strconv.Itoa(i int) string
整数转字符串
Atoi
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
获取日期信息
包括但不只有下面这些方法,全部的方法去官网查吧:
- func (t Time) Date() (year int, month Month, day int) {} // 返回时间的日期信息
- func (t Time) Year() int {} // 返回年
- func (t Time) Month() Month {} // 月
- func (t Time) Day() int {} // 日
- func (t Time) Weekday() Weekday {} // 星期
- func (t Time) ISOWeek() (year, week int) {} // 返回年,星期范围编号
- func (t Time) Clock() (hour, min, sec int) {} // 返回时间的时分秒
- func (t Time) Hour() int {} // 返回小时
- func (t Time) Minute() int {} // 分钟
- func (t Time) Second() int {} // 秒
- func (t Time) Nanosecond() int {} // 纳秒
- func (t Time) YearDay() int {} // 一年中对应的天
- func (t Time) Location() *Location {} // 时间的时区
- func (t Time) Zone() (name string, offset int) {} // 时间所在时区的规范名和想对UTC 时间偏移量
- func (t Time) Unix() int64 {} // 时间转为时间戳
- func (t Time) UnixNano() int64 {} // 时间转为时间戳(纳秒)
示例:
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 / else 分支判断
语法:
// 第一种 if condition1 { } // 第二种 if condition1 { } else { } // 第三种 if condition 1 { } else if condition2 { } else if condition3 { } else { }
switch case 语句
语法:
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循环的 } } }
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:结束本次循环,进入下一次继续
label
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语句中的变量的值,在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> */
用途
- 关闭文件句柄
- 操作前给资源上锁,用defer释放锁
- 数据库连接释放
以关闭文件句柄举例:
func read () { file := open(filename) // 打开了一个文件 defer file.Close() // 紧接着用defer关闭这个文件 // 之后再写各种文件操作 // 到文件返回时,defer就会执行,关闭这个文件句柄 }
使用defer不踩坑
函数返回的过程是这样子的:先给返回值赋值,然后调用defer表达式,最后才是返回到调用函数中。
defer表达式可能会在设置函数返回值之后,在返回到调用函数之前,修改返回值,使最终的函数返回值与你想象的不一致。
课后作业
一、编写程序,在终端输出九九乘法表
二、一个数如果恰好等于他的因子只和,那么这个数就称为“完数”。例如6=1+2+3。编程找出1000以内的所有完数。
三、输入一个字符串,判断其是否为回文。回文字符串是指从左到右读和从右到左读完全相同的字符串。
四、输入一行字符,分别统计出其中英文字母、空格、数字和其它字符的个数。
五、计算两个大数相加的和,这两个大数会超过int64的表示范围。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 编译型语言、解释型语言、静态类型语言、动态类型语言概念与区别
- 计算机语言发展的三个阶段:机器语言、汇编语言与高级语言
- 凹 (“Wa”) 语言:可以嵌入 Go 语言环境的脚本语言
- Rust语言恰巧是一门解决了Go语言所有问题的语言
- 获取系统语言/当前 App支持语言
- 【Go 语言教程】Go 语言简介
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
MATLAB高效编程技巧与应用
吴鹏 / 北京航空航天大学 / 2010-6 / 39.00元
《MATLAB高效编程技巧与应用:25个案例分析》是作者八年MATLAB使用经验的总结,精心设计的所有案例均来自于国内各大MATLAB技术论坛网友的切身需求,其中不少案例涉及的内容和求解方法在国内现已出版的MATLAB书籍中鲜有介绍。 《MATLAB高效编程技巧与应用:25个案例分析》首先针对MATLAB新版本特有的一些编程思想、高效的编程方法、新技术进行了较为详细的讨论,在此基础上,以大量......一起来看看 《MATLAB高效编程技巧与应用》 这本书的介绍吧!