go-mapper
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGo Mapper
Go Mapper
Generate pure mapper functions for GO modular architecture.
为Go模块化架构生成纯mapper函数。
When to Use
适用场景
- Map HTTP request DTOs to use case inputs
- Map persistence models to HTTP response DTOs
- Map between any two struct representations across layers
- Convert a slice of structs to a slice of another struct
- Any struct-to-struct transformation that lives in a module
- 将HTTP请求DTO映射为用例输入
- 将持久化模型映射为HTTP响应DTO
- 跨层的任意两种struct表示之间的映射
- 将struct切片转换为另一种struct的切片
- 模块内的任意struct到struct的转换
Location
文件位置
All mapper files live in .
internal/modules/<module>/mapper/One file per domain concept: (e.g., ).
<name>_mapper.gouser_mapper.go所有mapper文件都存放在路径下。
internal/modules/<module>/mapper/每个领域概念对应一个文件:(例如)。
<name>_mapper.gouser_mapper.goFunction Signature Pattern
函数签名规范
Every mapper function follows the prefix convention. It accepts one or more inputs and returns exactly one output, optionally with an error.
Tofunc ToXxx(input InputType) OutputType
func ToXxx(input InputType) (OutputType, error)
func ToXxx(a TypeA, b TypeB) OutputTypeSingle output only. Error is the only allowed second return value.
每个mapper函数都遵循前缀的约定。它接收一个或多个输入,仅返回一个输出,可选择额外返回error。
Tofunc ToXxx(input InputType) OutputType
func ToXxx(input InputType) (OutputType, error)
func ToXxx(a TypeA, b TypeB) OutputType仅允许单个返回值,error是唯一允许的第二个返回值。
File Structure
文件结构
- Package declaration and imports
- Public mapper functions
- Private helper functions (shared logic between public functions)
- 包声明与导入
- 公共mapper函数
- 私有辅助函数(公共函数之间的共享逻辑)
Examples
示例
Basic mapper
基础mapper
go
package mapper
import (
"github.com/cristiano-pacheco/pingo/internal/modules/user/dto"
"github.com/cristiano-pacheco/pingo/internal/modules/user/model"
"github.com/cristiano-pacheco/pingo/internal/modules/user/usecase"
)
func ToCreateUserInput(req dto.CreateUserRequest) usecase.CreateUserInput {
return usecase.CreateUserInput{
Name: req.Name,
Email: req.Email,
}
}
func ToUserResponse(u model.UserModel) dto.UserResponse {
return dto.UserResponse{
ID: u.ID,
Name: u.Name,
Email: u.Email,
CreatedAt: u.CreatedAt,
}
}
func ToUserListResponse(models []model.UserModel) []dto.UserResponse {
responses := make([]dto.UserResponse, len(models))
for i, u := range models {
responses[i] = ToUserResponse(u)
}
return responses
}go
package mapper
import (
"github.com/cristiano-pacheco/pingo/internal/modules/user/dto"
"github.com/cristiano-pacheco/pingo/internal/modules/user/model"
"github.com/cristiano-pacheco/pingo/internal/modules/user/usecase"
)
func ToCreateUserInput(req dto.CreateUserRequest) usecase.CreateUserInput {
return usecase.CreateUserInput{
Name: req.Name,
Email: req.Email,
}
}
func ToUserResponse(u model.UserModel) dto.UserResponse {
return dto.UserResponse{
ID: u.ID,
Name: u.Name,
Email: u.Email,
CreatedAt: u.CreatedAt,
}
}
func ToUserListResponse(models []model.UserModel) []dto.UserResponse {
responses := make([]dto.UserResponse, len(models))
for i, u := range models {
responses[i] = ToUserResponse(u)
}
return responses
}Mapper with multiple inputs
多输入mapper
go
package mapper
import (
"github.com/cristiano-pacheco/pingo/internal/modules/order/dto"
"github.com/cristiano-pacheco/pingo/internal/modules/order/model"
)
func ToOrderResponse(order model.OrderModel, items []model.OrderItemModel) dto.OrderResponse {
return dto.OrderResponse{
ID: order.ID,
Total: order.Total,
Items: toOrderItemResponses(items),
}
}
func toOrderItemResponses(items []model.OrderItemModel) []dto.OrderItemResponse {
responses := make([]dto.OrderItemResponse, len(items))
for i, item := range items {
responses[i] = dto.OrderItemResponse{
ID: item.ID,
Name: item.ProductName,
Quantity: item.Quantity,
Price: item.Price,
}
}
return responses
}go
package mapper
import (
"github.com/cristiano-pacheco/pingo/internal/modules/order/dto"
"github.com/cristiano-pacheco/pingo/internal/modules/order/model"
)
func ToOrderResponse(order model.OrderModel, items []model.OrderItemModel) dto.OrderResponse {
return dto.OrderResponse{
ID: order.ID,
Total: order.Total,
Items: toOrderItemResponses(items),
}
}
func toOrderItemResponses(items []model.OrderItemModel) []dto.OrderItemResponse {
responses := make([]dto.OrderItemResponse, len(items))
for i, item := range items {
responses[i] = dto.OrderItemResponse{
ID: item.ID,
Name: item.ProductName,
Quantity: item.Quantity,
Price: item.Price,
}
}
return responses
}Mapper with error return
带error返回的mapper
Use when transformation can fail (e.g., parsing, validation during mapping).
go
package mapper
import (
"github.com/cristiano-pacheco/pingo/internal/modules/product/dto"
"github.com/cristiano-pacheco/pingo/internal/modules/product/errs"
"github.com/cristiano-pacheco/pingo/internal/modules/product/model"
)
func ToProductModel(req dto.CreateProductRequest) (model.ProductModel, error) {
price, err := parsePrice(req.Price)
if err != nil {
return model.ProductModel{}, errs.ErrInvalidPrice
}
return model.ProductModel{
Name: req.Name,
Price: price,
}, nil
}当转换可能失败时使用(例如映射过程中的解析、校验场景)。
go
package mapper
import (
"github.com/cristiano-pacheco/pingo/internal/modules/product/dto"
"github.com/cristiano-pacheco/pingo/internal/modules/product/errs"
"github.com/cristiano-pacheco/pingo/internal/modules/product/model"
)
func ToProductModel(req dto.CreateProductRequest) (model.ProductModel, error) {
price, err := parsePrice(req.Price)
if err != nil {
return model.ProductModel{}, errs.ErrInvalidPrice
}
return model.ProductModel{
Name: req.Name,
Price: price,
}, nil
}Slice mapper pattern
切片mapper模式
When mapping a single item, add a corresponding list function if the type appears in collections.
go
func ToArticleResponse(a model.ArticleModel) dto.ArticleResponse {
return dto.ArticleResponse{
ID: a.ID,
Title: a.Title,
Author: toAuthorResponse(a),
}
}
func ToArticleListResponse(models []model.ArticleModel) []dto.ArticleResponse {
responses := make([]dto.ArticleResponse, len(models))
for i, a := range models {
responses[i] = ToArticleResponse(a)
}
return responses
}
func toAuthorResponse(a model.ArticleModel) dto.AuthorResponse {
return dto.AuthorResponse{
ID: a.AuthorID,
Name: a.AuthorName,
}
}映射单个对象时,如果该类型会以集合形式出现,需要新增对应的列表转换函数。
go
func ToArticleResponse(a model.ArticleModel) dto.ArticleResponse {
return dto.ArticleResponse{
ID: a.ID,
Title: a.Title,
Author: toAuthorResponse(a),
}
}
func ToArticleListResponse(models []model.ArticleModel) []dto.ArticleResponse {
responses := make([]dto.ArticleResponse, len(models))
for i, a := range models {
responses[i] = ToArticleResponse(a)
}
return responses
}
func toAuthorResponse(a model.ArticleModel) dto.AuthorResponse {
return dto.AuthorResponse{
ID: a.AuthorID,
Name: a.AuthorName,
}
}Naming
命名规范
- File: in
<name>_mapper.gopackagemapper/ - Public functions: — where
ToXxxis the output type name (e.g.,Xxx,ToUserResponse)ToCreateUserInput - Private helpers: — lowercase prefix for shared sub-mapping logic
toXxx - Slice variants: or
ToXxxListToXxxListResponse
- 文件:包下的
mapper/<name>_mapper.go - 公共函数:—— 其中
ToXxx是输出类型的名称(例如Xxx、ToUserResponse)ToCreateUserInput - 私有辅助函数:—— 共享的子映射逻辑使用小写前缀
toXxx - 切片变种:或
ToXxxListToXxxListResponse
Rules
规则
- Functions only — no structs, no interfaces, no constructors, no port files
- prefix — every public function starts with
ToTo - Single output — one return value, or one return value + error
- No — mappers are pure transformations, no I/O
context.Context - No side effects — no logging, no database calls, no external dependencies
- Private helpers — extract shared sub-mapping logic into private functions
- No comments on functions — function names are self-documenting via the convention
To - Slice helpers — add a list variant when the mapped type appears in collections
- Error return only when transformation can fail — prefer no-error signatures; use error only for parsing or conversion failures
- 仅包含函数 —— 不允许struct、接口、构造函数、端口文件
- 前缀 —— 所有公共函数都以
To开头To - 单输出 —— 仅一个返回值,或一个返回值+error
- 不允许传入—— mapper是纯转换逻辑,无I/O操作
context.Context - 无副作用 —— 不允许日志、数据库调用、外部依赖
- 私有辅助函数 —— 将共享的子映射逻辑提取到私有函数中
- 无需给函数加注释 —— 遵循命名约定的函数名本身就具备自说明性
To - 切片辅助函数 —— 当被映射的类型会以集合形式出现时,新增对应的列表转换变种
- 仅当转换可能失败时才返回error —— 优先使用无error的签名;仅在解析或转换失败的场景下使用error返回
Workflow
工作流程
- Create mapper file in
mapper/<name>_mapper.go - Run to verify code quality
make lint - Run for static analysis
make nilaway
- 在路径下创建mapper文件
mapper/<name>_mapper.go - 运行验证代码质量
make lint - 运行执行静态分析
make nilaway