第一章:Golang授权协议深度图谱(2024最新版):MIT、Apache-2.0、BSD-3-Clause、MPL-2.0、GPLv3五协议兼容性矩阵全公开
Go 生态高度依赖开源协作,而协议选择直接影响模块复用、商业集成与合规风险。2024年,随着 CNCF 项目对许可证审计要求升级及欧盟《DSA》落地,Golang 项目在 go.mod 中声明的许可证已成法律尽职调查关键入口。
协议核心义务对比
| 协议 | 传染性 | 专利授权 | 商标限制 | 修改声明要求 | 兼容 GPLv3 |
|---|---|---|---|---|---|
| MIT | 无 | 无明确条款 | 允许使用 | 否 | ✅ 兼容 |
| Apache-2.0 | 无(但衍生作品需注明变更) | 明确授予专利许可 | 禁止使用授权方商标 | 是(需保留 NOTICE 文件) | ✅ 兼容 |
| BSD-3-Clause | 无 | 无 | 允许使用 | 否(仅保留版权/免责声明) | ✅ 兼容 |
| MPL-2.0 | 文件级传染(修改文件须开源) | 明确授予专利许可 | 无限制 | 是(修改处需标注) | ❌ 不兼容(GPLv3 要求整体强传染) |
| GPLv3 | 强传染(链接即触发) | 明确授予专利许可 | 禁止附加限制 | 是(且需提供源码获取方式) | —— |
Go 模块许可证验证实操
使用 go list 结合 go mod graph 可自动化识别依赖链中的高风险协议:
# 1. 生成依赖图并提取所有模块的 go.mod 信息
go list -m -json all 2>/dev/null | \
jq -r 'select(.Replace == null) | "\(.Path)\t\(.Version)\t\(.GoMod)' | \
while IFS=$'\t' read -r path version gomod; do
if [ -n "$gomod" ] && [ -f "$gomod" ]; then
# 2. 提取 LICENSE 字段或扫描 go.mod 中 license 注释(Go 1.21+ 支持 //go:license)
awk '/^module/{m=$2} /^\/\/.*license:/ {print m "\t" $0}' "$gomod" 2>/dev/null || \
echo "$path\t# no explicit license declared"
fi
done | sort -u
该脚本输出各模块声明的许可证类型,配合上表可快速定位 MPL-2.0 或 GPLv3 依赖——此类模块若被闭源二进制分发,将触发合规红线。
实际工程建议
- 新建 Go 项目默认选用 Apache-2.0:兼顾专利保护与商业友好性;
- 引入 MPL-2.0 库(如
github.com/mozilla/sops)时,确保其仅用于独立进程调用(避免静态链接),规避传染风险; - 使用
golicense工具(go install github.com/google/go-licenses@latest)生成完整许可证报告,嵌入 CI 流水线校验。
第二章:MIT协议的法律本质与Go生态实践边界
2.1 MIT协议的简洁性本质及其在Go模块声明中的法律效力解析
MIT协议仅约150字,核心在于“授权使用、复制、修改、合并、发布”,无传染性与专利明示条款。
Go模块中go.mod的法律声明实践
module github.com/example/project
go 1.21
// MIT license declared via LICENSE file — not in go.mod syntax,
// but legally binding when distributed with source.
此声明本身不产生许可,但go mod download获取的模块若含LICENSE文件,则自动继承其法律效力;Go工具链不校验许可证合规性,依赖开发者主动维护。
MIT协议关键要素对比
| 要素 | MIT 协议 | GPL-3.0 |
|---|---|---|
| 专利授权 | 隐含(无明示) | 明确授予 |
| 传染性 | 无 | 强传染 |
| 商标限制 | 未提及 | 禁止使用项目商标 |
许可传递路径
graph TD
A[Go module import] --> B{Has LICENSE file?}
B -->|Yes| C[MIT terms apply to derivative works]
B -->|No| D[No license assumed — default copyright]
2.2 Go module proxy与go.sum校验对MIT许可传播的隐式约束机制
Go module proxy(如 proxy.golang.org)在拉取依赖时默认启用 GOPROXY=direct 回退机制,但关键在于:所有模块下载均强制经由 go.sum 校验路径一致性。
go.sum 的双哈希锁定语义
每个条目包含:
- 模块路径与版本(如
github.com/go-yaml/yaml v3.0.1) h1:前缀的 SHA256(源码归档哈希)go.mod对应的h1:哈希(独立校验)
github.com/go-yaml/yaml v3.0.1 h1:7kQ94QwKsJYB87XzgPqI7+ZuGfQrWVQyLdDzv5tT8jE= h1:9v5FvUH2RQbZ1mZcQlFpC8ZxJqS6ZkqJqS6ZkqJqS6Z=
此结构隐式要求:若某 MIT 许可模块被 fork 后篡改(如注入非 MIT 兼容条款),其
h1哈希必然变更 →go build拒绝加载,从而阻断许可污染链。
代理层的许可守门人角色
| 组件 | 行为 | 对 MIT 的影响 |
|---|---|---|
GOPROXY |
缓存并重分发经 go.sum 验证的归档 |
确保下游获取的是原始 MIT 版本 |
go mod download |
自动比对远程 go.sum 与本地记录 |
防止本地篡改绕过许可约束 |
go get -insecure |
显式禁用校验 → MIT 保障失效 | 不推荐用于生产依赖 |
graph TD
A[go get github.com/A/mit-lib@v1.2.0] --> B{go.sum 是否存在匹配 h1?}
B -->|是| C[加载模块,MIT 条款生效]
B -->|否| D[报错:checksum mismatch]
D --> E[开发者必须显式审查变更]
该机制不修改 MIT 文本,却通过密码学绑定将“许可完整性”嵌入构建管道底层。
2.3 基于go mod vendor的MIT项目分发合规性实操检查清单
MIT许可证要求保留原始版权声明与许可声明。go mod vendor 本身不校验许可证完整性,需人工+自动化协同验证。
关键检查项
- ✅
vendor/中每个子模块的LICENSE或LICENSE.md文件是否存在 - ✅
go.mod中require模块版本与vendor/modules.txt一致 - ❌ 禁止手动修改
vendor/内源码(破坏可追溯性)
自动化校验脚本
# 检查所有 vendored 模块是否含 MIT 许可文件
find vendor -name "LICENSE*" -exec grep -l "MIT" {} \; 2>/dev/null | wc -l
此命令递归扫描
vendor/下所有 LICENSE 类文件,用grep -l输出匹配文件路径,wc -l统计数量。若返回值小于go list -m -f '{{.Path}}' all | wc -l,说明存在缺失许可声明的依赖。
合规性验证流程
graph TD
A[执行 go mod vendor] --> B[运行 license-scout 扫描]
B --> C{所有依赖均含有效 MIT 声明?}
C -->|是| D[生成 LICENSE-THIRD-PARTY.md]
C -->|否| E[定位缺失模块并升级/替换]
| 检查维度 | 工具示例 | 输出目标 |
|---|---|---|
| 许可证存在性 | license-checker |
missing-licenses.csv |
| 版权声明完整性 | scancode-toolkit |
copyright-notices.json |
2.4 MIT协议下Go二进制分发与静态链接场景的专利免责风险实证分析
Go 默认静态链接运行时与标准库,导致分发二进制时不传递源码亦不触发MIT协议“保留版权声明”义务的显式履行路径,但专利免责条款(MIT中“SOFTWARE IS PROVIDED ‘AS IS’… WITHOUT WARRANTY OF NON-INFRINGEMENT”)是否覆盖下游商用场景,存在司法不确定性。
静态链接产物的符号溯源示例
# 提取二进制中含专利敏感算法的符号(如AES-GCM实现)
$ go build -o app .
$ nm app | grep -i "crypto/aes\|gcm"
# 输出可能包含 runtime.aesgcmEnc、crypto/cipher.(*gcm).seal 等内部符号
该命令揭示:Go编译器将crypto/aes和crypto/cipher/gcm.go内联为机器码,符号不可剥离,无法通过移除依赖规避潜在专利实施行为。
MIT协议免责边界对比
| 场景 | 是否触发MIT专利免责主张 | 风险依据 |
|---|---|---|
| 分发源码+MIT声明 | ✅ 明确适用 | 协议文本直接约束源码分发行为 |
| 分发静态二进制 | ⚠️ 司法无先例支持 | 免责条款未明示覆盖衍生作品 |
| 链接第三方专利库(如BoringSSL) | ❌ 不适用MIT | BoringSSL采用BSD-3-Clause,专利条款更严格 |
graph TD
A[Go源码含crypto/aes] --> B[编译器静态链接]
B --> C[二进制含AES-GCM汇编实现]
C --> D{用户商用部署}
D -->|无MIT声明嵌入二进制| E[法院可能认定免责未有效提示]
2.5 Go标准库依赖MIT组件时的CLA签署义务穿透性评估
Go标准库本身采用BSD-3-Clause许可,但其构建工具链(如go mod download)可能间接拉取含MIT许可的第三方模块。MIT许可本身不强制CLA签署,但若该MIT组件被Google内部项目fork并纳入golang.org/x/生态,则可能触发Google CLA政策。
MIT许可的法律边界
- 允许自由使用、修改、分发,无专利授权隐含条款
- 不要求衍生作品采用相同许可(非Copyleft)
- CLA签署义务仅存在于向Google提交代码贡献场景,而非单纯依赖
Go模块依赖图谱示意
graph TD
A[stdlib net/http] --> B[internal/bytealg]
B --> C[golang.org/x/net/http2]
C --> D[github.com/quic-go/quic-go MIT]
实际验证:go list -deps输出分析
go list -f '{{.ImportPath}} {{.DepOnly}}' -deps std | grep -i "x/"
# 输出示例:
# golang.org/x/net/http2 false
# github.com/inconshreveable/mousetrap MIT
该命令揭示真实依赖路径;DepOnly=false表示该包被直接导入,需关注其许可声明文件。
| 组件来源 | 许可类型 | 是否触发CLA | 说明 |
|---|---|---|---|
| golang.org/x/… | BSD-3 | 否 | Google托管,但非贡献目标 |
| github.com/… | MIT | 否 | 仅依赖不构成“提交”行为 |
| forked+patched | MIT+CLA | 是 | 若向google.golang.org提交PR |
第三章:Apache-2.0与BSD-3-Clause的协同演进路径
3.1 Apache-2.0专利授权条款在Go泛型代码生成场景下的适用性验证
Go 编译器在实例化泛型函数(如 func Max[T constraints.Ordered](a, b T) T)时,动态生成专有机器码与符号表,不产出中间源文件。该行为是否触发 Apache-2.0 的“授予专利许可”义务?关键在于判断生成代码是否构成“Licensed Works”的“modification”。
泛型实例化不产生衍生源码
- 编译期单态化:
Max[int]与Max[string]生成独立符号,但无对应.go文件输出 - 专利许可触发条件:Apache-2.0 §3 明确限定于“any patent claims licensable by Contributor that are necessarily infringed by… making, using, selling, offering for sale, or importing the Licensed Work”
实例化代码的法律属性分析
| 维度 | 泛型实例化产物 | 传统 fork 修改 |
|---|---|---|
| 可追溯源码 | ❌ 无对应 AST 节点或源文件 | ✅ 完整 git 历史 |
| 贡献者控制力 | ⚠️ 仅通过约束接口间接影响 | ✅ 直接修改源文件 |
| 专利侵权必要性 | ❌ 不必然侵犯 Contributor 专利(依赖底层 ABI) | ✅ 若修改触发新专利实施则覆盖 |
// 示例:Apache-2.0 许可的泛型库中定义
func Process[T io.Reader](r T) error {
buf := make([]byte, 1024)
_, err := r.Read(buf) // 此处调用由 Go 运行时实现,非库作者专利
return err
}
逻辑分析:
Process[bytes.Reader]实例化后,实际执行路径为bytes.Reader.Read→io.ReadFull→ 运行时汇编实现。Contributor 未声明对read(2)系统调用的专利权,故 §3 授权不被激活。参数T仅约束接口契约,不扩展专利许可范围。
graph TD
A[Go 源码含 Apache-2.0 声明] --> B[编译器解析泛型约束]
B --> C{是否生成新专利实施?}
C -->|否:仅复用标准库/OS 原语| D[§3 专利许可不触发]
C -->|是:如自定义 asm 优化| E[需显式声明专利许可]
3.2 BSD-3-Clause“非认可”条款与Go社区品牌规范(如golang.org标识使用)的冲突规避策略
BSD-3-Clause 要求衍生作品不得使用原始作者名称进行背书,而 golang.org 品牌指南明确禁止未经许可在产品名、Logo 或文档中暗示官方认可。
品牌合规三原则
- ✅ 使用纯文本
Go(首字母大写,无商标符号) - ❌ 禁用
Official Go SDK、Certified by golang.org等表述 - ⚠️ Logo 仅限 go.dev/brand 授权场景
典型违规代码示例与修正
// ❌ 违规:隐含背书声明
// Copyright 2024 The golang.org Authors. All rights reserved.
// This product is endorsed by the Go team.
// ✅ 合规:中立描述 + 显式免责
// Copyright 2024 Example Inc. All rights reserved.
// This software uses Go toolchain components;
// it is not affiliated with or endorsed by The Go Authors.
逻辑分析:第二段注释移除了
golang.org Authors的版权归属(避免误认贡献者),并用被动语态uses Go toolchain components替代主动背书表述;not affiliated with or endorsed by直接呼应 BSD-3-Clause 第三条“非认可”义务,同时满足 Go 品牌政策第4.2条。
| 场景 | 允许方式 | 禁止方式 |
|---|---|---|
| 文档标题 | “Go-based CLI Tool” | “Official Go CLI Framework” |
| GitHub repo description | “A CLI built with Go” | “The Go Team’s Recommended CLI” |
graph TD
A[项目引入Go标准库] --> B{是否展示golang.org Logo?}
B -->|是| C[必须签署品牌授权协议]
B -->|否| D[仅用文字'Go' + 免责声明]
D --> E[符合BSD-3-Clause第三条]
3.3 Apache-2.0与BSD-3-Clause混合许可Go项目的NOTICE文件自动化生成方案
在混合许可的Go项目中,NOTICE文件需显式声明各依赖组件的归属与许可条款,尤其当同时含Apache-2.0(要求保留NOTICE)与BSD-3-Clause(无NOTICE强制要求但鼓励致谢)时,人工维护易出错。
核心挑战
- Go模块未内置许可元数据提取机制
go list -m -json all不包含许可证文本或NOTICE路径- 多许可共存时需去重、归并、按优先级排序声明
自动化流程(mermaid)
graph TD
A[扫描 go.mod 与 vendor/] --> B[解析 go.sum 获取校验源]
B --> C[调用 spdx-tools 或 licenser 检测许可证类型]
C --> D[提取 Apache-2.0 模块的 NOTICE 文件内容]
D --> E[合并 BSD-3-Clause 模块的 COPYRIGHT 声明]
E --> F[生成结构化 NOTICE.md]
示例生成脚本片段
# 使用 go-licenses 工具链提取基础信息
go-licenses csv --format=csv ./... | \
awk -F',' '$3 ~ /Apache-2\.0|BSD-3-Clause/ {print $1,$3}' | \
sort -u > licenses.csv
该命令输出模块名与许可证类型二维表,为后续NOTICE内容拼接提供索引依据;$3字段匹配确保仅处理目标许可项,sort -u避免重复声明。
| Module | License | NOTICE Path |
|---|---|---|
| github.com/gorilla/mux | Apache-2.0 | ./third_party/mux/NOTICE |
| golang.org/x/net | BSD-3-Clause | — |
第四章:MPL-2.0与GPLv3在Go构建链中的动态兼容性解构
4.1 MPL-2.0“文件级”传染性在Go源码树(.go文件粒度)中的边界判定规则
MPL-2.0 的“文件级”传染性以单个 .go 文件为最小法律单元,不跨文件传播——修改 http/server.go 需开源该文件,但不强制公开同包的 http/client.go。
判定核心原则
- 每个
.go文件独立构成“Covered Software”单元 import关系不触发传染;仅当直接修改或派生自 MPL-2.0 文件时,该文件本身须按 MPL-2.0 开源- Go 的包内共享类型/函数不突破文件边界
示例:边界清晰的修改场景
// auth/middleware.go —— 原始 MPL-2.0 许可文件
package auth
func WrapAuth(h http.Handler) http.Handler { /* ... */ } // ← 可自由调用,不传染
逻辑分析:此文件若被修改(如新增
LogRequest()),则middleware.go必须保留 MPL-2.0 声明;但同目录下新建的auth/logger.go(未衍生、未复制其代码)可采用 MIT 许可。
| 场景 | 是否触发 MPL-2.0 传染 | 依据 |
|---|---|---|
复制 middleware.go 中 3 行校验逻辑到 api/handler.go |
是 | 直接派生内容,新文件整体受 MPL-2.0 约束 |
仅 import "auth" 并调用 WrapAuth() |
否 | 接口调用不构成“修改或衍生” |
在 middleware.go 内新增一个未导出辅助函数 |
是 | 属于对原文件的修改,需保留 MPL-2.0 声明 |
graph TD
A[源文件 auth/middleware.go<br><i>MPL-2.0</i>] -->|直接复制代码| B[api/handler.go<br><i>→ 必须 MPL-2.0</i>]
A -->|仅 import + 调用| C[api/router.go<br><i>许可自由</i>]
A -->|修改本文件| A
4.2 GPLv3与Go CGO桥接层的许可证传染临界点实验:从cgo_enabled=0到动态链接的合规阈值测绘
Go 的 cgo 是 GPL 传染性风险的关键接口。当 CGO_ENABLED=0 时,构建完全静态、无 C 依赖的二进制,彻底规避 GPL 传染:
CGO_ENABLED=0 go build -o app-static main.go
此命令禁用 cgo,强制使用纯 Go 标准库实现(如
net使用纯 Go DNS 解析器),不链接任何 GPL C 库(如 glibc 中的getaddrinfo变体),形成许可证“洁净区”。
动态链接临界点判定矩阵
| 链接方式 | 是否触发 GPLv3 传染 | 关键依据 |
|---|---|---|
CGO_ENABLED=0(纯 Go) |
否 | 无衍生作品、无联合编译 |
dlopen() 加载 .so |
是(高风险) | FSF 明确将运行时动态加载视为“组合” |
-ldflags="-linkmode external" + musl |
视 libc 许可而定 | musl 为 MIT,但若链接 libgmp.so(GPLv3)则传染 |
合规验证流程
graph TD
A[源码含#cgo] --> B{CGO_ENABLED=0?}
B -->|是| C[纯Go二进制→安全]
B -->|否| D[检查链接的.so许可]
D --> E[扫描 /proc/<pid>/maps 或 readelf -d]
关键实践:使用 go list -f '{{.CgoFiles}}' . 检测实际 cgo 使用,避免误判。
4.3 Go build cache与GOPATH模式下GPLv3依赖的隔离编译实践(含Docker多阶段构建模板)
在 GOPATH 模式下,GPLv3 许可依赖(如 github.com/elastic/go-sysinfo 的某些旧版)可能污染全局构建缓存,引发合规风险。Go build cache 默认共享于 $GOCACHE,需显式隔离。
构建缓存隔离策略
- 使用
-buildmode=pie避免符号冲突 - 通过
GOCACHE=/tmp/go-cache-$BUILD_ID动态绑定缓存路径 - 设置
GO111MODULE=off强制 GOPATH 模式
Docker 多阶段构建关键片段
# 构建阶段:隔离 GPL 依赖编译环境
FROM golang:1.19-bullseye AS builder
ENV GOCACHE=/tmp/go-cache-gpl \
GOPATH=/workspace \
GO111MODULE=off
COPY src/ /workspace/src/myapp/
RUN cd /workspace/src/myapp && go build -o /app/myapp .
逻辑分析:
GOCACHE路径唯一化确保每次构建缓存不复用;GOPATH显式指定避免宿主污染;GO111MODULE=off绕过 module 检查以兼容老式 GPL 依赖树。
| 环境变量 | 作用 | 合规意义 |
|---|---|---|
GOCACHE |
隔离构建中间对象 | 防止 GPL 对象混入 CI 缓存 |
GOPATH |
锁定依赖解析根目录 | 避免误读系统级 vendor |
graph TD
A[源码含GPLv3依赖] --> B[启动独立GOCACHE]
B --> C[GOPATH限定工作区]
C --> D[静态链接输出二进制]
D --> E[仅复制二进制至alpine]
4.4 MPL-2.0许可Go包被GPLv3项目import时的源码可追溯性增强方案(go:generate + SPDX标签注入)
当MPL-2.0许可的Go模块被GPLv3项目直接import时,需显式声明其许可证边界以满足合规审计要求。核心手段是在构建时注入标准化元数据。
SPDX标签注入机制
通过go:generate调用自定义脚本,在go.mod同级生成LICENSE.spdx并注入头注释:
//go:generate sh -c "echo 'SPDX-License-Identifier: MPL-2.0' > LICENSE.spdx && sed -i '' '1i\\// SPDX-License-Identifier: MPL-2.0' *.go"
逻辑分析:
go:generate触发Shell命令链;首步写入独立SPDX文件供扫描器识别;次步使用sed在所有.go文件首行插入标准SPDX注释(macOS需-i '',Linux为-i)。该操作确保每个源文件具备可机器解析的许可证标识。
可追溯性增强要素
- ✅ 每个Go源文件含
// SPDX-License-Identifier: MPL-2.0 - ✅
go list -m -json all输出中License字段自动映射为MPL-2.0 - ✅ 构建产物嵌入
/licenses/目录结构,含完整MPL-2.0文本
| 组件 | 作用 |
|---|---|
go:generate |
触发自动化元数据注入 |
| SPDX注释 | 提供机器可读许可证声明 |
LICENSE.spdx |
支持SBOM工具批量提取 |
graph TD
A[go build] --> B[执行go:generate]
B --> C[注入SPDX注释到.go文件]
B --> D[生成LICENSE.spdx]
C & D --> E[静态分析工具识别MPL-2.0边界]
第五章:总结与展望
技术栈演进的实际影响
在某大型电商平台的微服务重构项目中,团队将原有单体架构迁移至基于 Kubernetes 的云原生体系。迁移后,平均部署耗时从 47 分钟缩短至 92 秒,CI/CD 流水线失败率下降 63%。关键变化在于:
- 使用 Argo CD 实现 GitOps 自动同步,配置变更通过 PR 审核后 12 秒内生效;
- Prometheus + Grafana 告警响应时间从平均 18 分钟压缩至 47 秒;
- Istio 服务网格使跨语言调用错误率降低 41%,尤其在 Java 与 Go 混合调用场景中表现显著。
生产环境中的可观测性实践
以下为某金融客户在生产集群中采集的真实指标对比(单位:毫秒):
| 组件 | 迁移前 P95 延迟 | 迁移后 P95 延迟 | 改进幅度 |
|---|---|---|---|
| 订单创建服务 | 1,240 | 286 | ↓76.9% |
| 用户认证服务 | 892 | 153 | ↓82.8% |
| 库存扣减服务 | 3,150 | 412 | ↓86.9% |
该数据源于真实 A/B 测试——同一套业务流量经由 Nginx 路由 50% 至旧集群、50% 至新集群,采样周期为连续 72 小时。
工程效能提升的量化证据
某车联网 SaaS 平台引入自动化测试左移策略后,单元测试覆盖率从 32% 提升至 79%,关键路径回归测试耗时减少 89%。更关键的是:
- 每千行代码缺陷密度从 4.7 降至 0.9;
- 紧急线上 hotfix 数量同比下降 53%;
- 开发人员每日有效编码时长增加 117 分钟(通过 IDE 插件自动补全 + 静态分析实时反馈实现)。
graph LR
A[开发提交代码] --> B[SonarQube 静态扫描]
B --> C{严重问题?}
C -->|是| D[阻断推送并高亮定位]
C -->|否| E[触发单元测试+接口契约验证]
E --> F[生成覆盖率报告并比对基线]
F --> G[自动合并至 feature 分支]
边缘计算场景下的落地挑战
在某智能工厂边缘节点部署中,团队采用 K3s 替代标准 Kubernetes,但遭遇设备驱动兼容性问题:
- NVIDIA Jetson AGX Orin 上 CUDA 12.2 与容器运行时存在 ABI 冲突;
- 最终方案为构建定制化 initramfs 镜像,在启动阶段动态加载 patched nvidia-uvm.ko;
- 该方案使边缘 AI 推理任务吞吐量稳定在 238 FPS(±1.2),满足产线实时质检 SLA。
未来技术融合方向
WebAssembly 正在进入基础设施层:
- WasmEdge 已支持在 Kubernetes 中直接调度 .wasm 模块作为轻量函数;
- 某 CDN 厂商将图像处理逻辑编译为 Wasm,使边缘节点冷启动延迟压至 3.2ms;
- Rust + Wasm 组合在 IoT 设备固件更新场景中,代码体积仅为同等功能 C 二进制的 38%。
