Daily Study
更新: 6/5/2025 字数: 0 字 时长: 0 分钟
Daily Plan
#todo
Lab1_MapReduce
go json相关
详细分析一下如下代码
go
package main
import (
"encoding/json"
"fmt"
"log"
"strings"
)
type Animal int
const (
Unknown Animal = iota
Gopher
Zebra
)
func (a *Animal) UnmarshalJSON(b []byte) error {
var s string
if err := json.Unmarshal(b, &s); err != nil {
return err
}
switch strings.ToLower(s) {
default:
*a = Unknown
case "gopher":
*a = Gopher
case "zebra":
*a = Zebra
}
return nil
}
func (a Animal) MarshalJSON() ([]byte, error) {
var s string
switch a {
default:
s = "unknown"
case Gopher:
s = "gopher"
case Zebra:
s = "zebra"
}
return json.Marshal(s)
}
func main() {
blob := `["gopher","armadillo","zebra","unknown","gopher","bee","gopher","zebra"]`
var zoo []Animal
if err := json.Unmarshal([]byte(blob), &zoo); err != nil {
log.Fatal(err)
}
census := make(map[Animal]int)
for _, animal := range zoo {
census[animal] += 1
}
fmt.Printf("Zoo Census:\n* Gophers: %d\n* Zebras: %d\n* Unknown: %d\n",
census[Gopher], census[Zebra], census[Unknown])
}
main
函数中blob
使用反引号,避免转义 JSON 字符串中的双引号,保持 JSON 格式的可读性[]byte
数组等价于[]uint8
,是一种字节切片类型,如下
go
str := "Hello"
bytes := []byte(str) // 字符串转换为字节切片
fmt.Println(bytes) // 输出: [72 101 108 108 111]
json
解析需要[]byte
,是因为func Unmarshal(data []byte, v interface{}) error
,有如下三个优点:- 性能考虑:避免字符串的不必要复制
- 内存效率:可以直接处理字节数据
- 通用性:可以处理任何来源的字节数据(文件、网络等)
os相关
1. 文件操作
go
// 打开文件(只读)
file, err := os.Open(reply.TaskName)
defer file.Close()
// 创建新文件
ofile, err := os.Create(oname)
// 以追加模式打开文件
ofile, err := os.OpenFile(oname, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
2. 文件状态检查
go
// 检查文件是否存在
if _, err := os.Stat(oname); os.IsNotExist(err) {
// 文件不存在
ofile, _ = os.Create(oname)
} else {
// 文件存在,以追加模式打开
ofile, _ = os.OpenFile(oname, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
}
3. 目录操作
go
// 读取目录内容
files, err := os.ReadDir(path)
if err != nil {
return err
}
// 遍历目录中的文件
for _, file := range files {
if file.IsDir() {
continue // 跳过子目录
}
fileName := file.Name()
// 处理文件...
}
4. 文件删除
go
// 删除文件
err := os.Remove(filePath)
if err != nil {
return err
}
// 删除 socket 文件
os.Remove(sockname)
### 5. 系统信息
// 获取用户ID
s += strconv.Itoa(os.Getuid())
// 程序退出
os.Exit(0) // 正常退出
os.Exit(-1) // 异常退出
Regexp
正则表达式书写:
// 基本字符匹配
^ // 行开始
$ // 行结束
. // 任意字符(除换行符)
* // 前面字符0次或多次
+ // 前面字符1次或多次
? // 前面字符0次或1次
\d // 数字字符 [0-9]
\w // 单词字符 [a-zA-Z0-9_]
\s // 空白字符
// 字符组
[abc] // 匹配 a、b 或 c
[a-z] // 匹配小写字母
[^abc] // 不匹配 a、b、c
// 量词
{n} // 恰好 n 次
{n,} // 至少 n 次
{n,m} // n 到 m 次
// 示例:匹配IP地址
ipPattern := `^(\d{1,3}\.){3}\d{1,3}$`
具体实现,匹配MapReduce
文件名:
go
import (
"fmt"
"regexp"
)
// 匹配 mr-out-{mapId}-{reduceId} 格式的文件
func matchMapOutputFiles(mapId int) *regexp.Regexp {
// 使用 \d+ 匹配一个或多个数字
pattern := fmt.Sprintf(`^mr-out-%d-\d+$`, mapId)
return regexp.MustCompile(pattern)
}
// 匹配 mr-out-{任意数字}-{特定reduceId} 格式的文件
func matchReduceInputFiles(reduceId int) *regexp.Regexp {
pattern := fmt.Sprintf(`^mr-out-\d+-%d$`, reduceId)
return regexp.MustCompile(pattern)
}