mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2024-11-28 09:09:07 +00:00
parent
55ba6736e9
commit
5e46274436
@ -60,6 +60,94 @@ func basename(s string) string {
|
|||||||
path 和 path/filepath 包提供了关于文件名更一般的函数操作. 使用斜杠分隔路径可以在任何操作系统上工作. 斜杠本身不应该用于文件名, 但是在其他一些领域可能是有效的, 例如URL路径组件. 相比之下, path/filepath 包使用操作系统本身的路径规则, 例如 POSIX 系统使用 /foo/bar, Microsoft Windows 使用 c:\foo\bar 等.
|
path 和 path/filepath 包提供了关于文件名更一般的函数操作. 使用斜杠分隔路径可以在任何操作系统上工作. 斜杠本身不应该用于文件名, 但是在其他一些领域可能是有效的, 例如URL路径组件. 相比之下, path/filepath 包使用操作系统本身的路径规则, 例如 POSIX 系统使用 /foo/bar, Microsoft Windows 使用 c:\foo\bar 等.
|
||||||
|
|
||||||
|
|
||||||
|
让我们继续另一个字符串的例子. 任务是将一个表示整值的字符串, 每隔三个字符插入一个逗号, 例如 "12345" 处理后成为 "12,345". 这个版本只适用于整数类型; 支持浮点数类型的支持留做练习.
|
||||||
|
|
||||||
|
```Go
|
||||||
|
gopl.io/ch3/comma
|
||||||
|
|
||||||
|
// comma inserts commas in a non-negative decimal integer string.
|
||||||
|
func comma(s string) string {
|
||||||
|
n := len(s)
|
||||||
|
if n <= 3 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return comma(s[:n-3]) + "," + s[n-3:]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
输入 comma 的参数是一个字符串. 如果输入字符串的长度小于或等于3的话, 则不需要插入逗号. 否则, comma 将在最后三个字符前切割为两个两个子串, 然后用前面的子串递归调用自身.
|
||||||
|
|
||||||
|
一个字符串包含的字节数组, 一旦创建, 是不可变的. 相比之下, 一个字节切片的原始则可以自由地修改.
|
||||||
|
|
||||||
|
字符串和字节切片可以相互转换:
|
||||||
|
|
||||||
|
```Go
|
||||||
|
s := "abc"
|
||||||
|
b := []byte(s)
|
||||||
|
s2 := string(b)
|
||||||
|
```
|
||||||
|
|
||||||
|
从概念上讲, []byte(s) 转换是分配了一个新的字节数组保存了字符串数据的拷贝, 然后引用这个字节数组. 编译器的优化可以避免在一些场景下分配和复制字符串数据, 但总的来说需要确保在b被修改的情况下, 原始的s字符串也不会改变. 将一个字节切片转到字符串的 string(b) 操作则是构造一个拷贝, 以确保s2字符串是只读的.
|
||||||
|
|
||||||
|
为了避免转换中不必要的内存分配, bytes包和strings同时提供了许多类似的实用函数. 下面是strings包中的六个函数:
|
||||||
|
|
||||||
|
```Go
|
||||||
|
func Contains(s, substr string) bool
|
||||||
|
func Count(s, sep string) int
|
||||||
|
func Fields(s string) []string
|
||||||
|
func HasPrefix(s, prefix string) bool
|
||||||
|
func Index(s, sep string) int
|
||||||
|
func Join(a []string, sep string) string
|
||||||
|
```
|
||||||
|
|
||||||
|
bytes 包中对应的六个函数:
|
||||||
|
|
||||||
|
```Go
|
||||||
|
func Contains(b, subslice []byte) bool
|
||||||
|
func Count(s, sep []byte) int
|
||||||
|
func Fields(s []byte) [][]byte
|
||||||
|
func HasPrefix(s, prefix []byte) bool
|
||||||
|
func Index(s, sep []byte) int
|
||||||
|
func Join(s [][]byte, sep []byte) []byte
|
||||||
|
```
|
||||||
|
|
||||||
|
唯一的区别是字符串类型参数被替换成了字节切片类型的参数.
|
||||||
|
|
||||||
|
bytes 包还提供了 Buffer 类型用于字节切片的缓存. 一个 Buffer 开始是空的, 但是随着 string, byte, 和 []byte 等类型数据的写入可以动态增长, 一个 bytes.Buffer 变量并不需要处理化, 因此零值也是有效的:
|
||||||
|
|
||||||
|
```Go
|
||||||
|
gopl.io/ch3/printints
|
||||||
|
|
||||||
|
// intsToString is like fmt.Sprintf(values) but adds commas.
|
||||||
|
func intsToString(values []int) string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
buf.WriteByte('[')
|
||||||
|
for i, v := range values {
|
||||||
|
if i > 0 {
|
||||||
|
buf.WriteString(", ")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&buf, "%d", v)
|
||||||
|
}
|
||||||
|
buf.WriteByte(']')
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Println(intsToString([]int{1, 2, 3})) // "[1, 2, 3]"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
当向 bytes.Buffer 添加任意字符的UTF8编码, 最好使用 bytes.Buffer 的 WriteRune 方法, 但是 WriteByte 方法对于写入类似 '[' 和 ']' 等 ASCII 字符则更有效.
|
||||||
|
|
||||||
|
bytes.Buffer 类型有着诸多实用的功能, 我们在第七章讨论接口时层涉及到, 我们将看看如何将它用作一个I/O 的输入和输出对象, 例如 Fprintf 的 io.Writer 输出, 或作为输入源 io.Reader.
|
||||||
|
|
||||||
|
**练习3.10:** 编写一个非递归版本的comma函数, 使用 bytes.Buffer 代替字符串链接操作.
|
||||||
|
|
||||||
|
**练习3.11:** 完善 comma 函数, 以支持浮点数处理和一个可选的正负号处理.
|
||||||
|
|
||||||
|
|
||||||
|
**练习3.12:** 编写一个函数, 判断两个字符串是否是是相互打乱的, 也就是说它们有着相同的字符, 但是对应不同的顺序.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
TODO
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user