@umacloud/knowledge 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/00-governance/governance-capabilities.md +557 -0
- package/00-governance/knowledge-map.md +39 -0
- package/00-governance/maintenance-policy.md +76 -0
- package/00-governance/review-checklist.md +81 -0
- package/README.md +13 -0
- package/ai/01-standards/agent-development-complete.md +691 -0
- package/ai/01-standards/llm-application-complete.md +488 -0
- package/ai/01-standards/mlops-complete.md +798 -0
- package/ai/01-standards/prompt-engineering-complete.md +646 -0
- package/ai/01-standards/rag-architecture-complete.md +649 -0
- package/ai/02-playbooks/llm-evaluation-playbook.md +847 -0
- package/ai/03-checklists/ai-project-checklist.md +215 -0
- package/ai/04-antipatterns/ai-antipatterns.md +661 -0
- package/ai/05-cases/case-rag-production.md +147 -0
- package/ai/06-glossary/ai-glossary.md +162 -0
- package/ai/agent-evaluation-benchmark.md +53 -0
- package/ai/ai-agent-memory-context-management.md +41 -0
- package/ai/ai-cost-capacity-optimization-playbook.md +42 -0
- package/ai/ai-data-security-and-compliance-playbook.md +37 -0
- package/ai/ai-domain-index-and-checklist.md +40 -0
- package/ai/ai-governance-maturity-model.md +50 -0
- package/ai/ai-model-selection-and-routing-strategy.md +47 -0
- package/ai/ai-observability-and-oncall-runbook.md +52 -0
- package/ai/ai-rag-engineering-playbook.md +42 -0
- package/ai/ai-red-team-and-safety-evaluation.md +42 -0
- package/ai/ai-release-readiness-and-rollback-gate.md +42 -0
- package/ai/llm-agent-engineering-deep-dive.md +57 -0
- package/ai/prompt-and-tool-guardrails.md +52 -0
- package/api/01-standards/enterprise-api-standards.md +198 -0
- package/api/01-standards/rest-api-design-guide.md +63 -0
- package/api/02-playbooks/api-pagination-playbook.md +93 -0
- package/api/02-playbooks/graphql-production-playbook.md +176 -0
- package/api/03-checklists/api-review-checklist.md +55 -0
- package/api/04-antipatterns/api-antipatterns.md +112 -0
- package/architecture/01-standards/api-gateway-patterns.md +496 -0
- package/architecture/01-standards/cloud-native-patterns.md +644 -0
- package/architecture/01-standards/distributed-systems-patterns.md +591 -0
- package/architecture/01-standards/event-driven-architecture.md +595 -0
- package/architecture/01-standards/microservices-patterns-complete.md +968 -0
- package/architecture/01-standards/microservices-patterns.md +495 -0
- package/architecture/01-standards/system-design-interview.md +664 -0
- package/architecture/02-playbooks/microservices-patterns-playbook.md +137 -0
- package/architecture/02-playbooks/migration-playbook.md +780 -0
- package/architecture/02-playbooks/system-design-playbook.md +779 -0
- package/architecture/03-checklists/architecture-decision-checklist.md +297 -0
- package/architecture/04-antipatterns/architecture-antipatterns.md +417 -0
- package/architecture/05-cases/case-netflix-microservices.md +413 -0
- package/architecture/06-glossary/architecture-glossary.md +164 -0
- package/architecture/adr-template-and-examples.md +38 -0
- package/architecture/api-gateway-deep-dive.md +1291 -0
- package/architecture/configuration-management.md +1162 -0
- package/architecture/distributed-transactions.md +1220 -0
- package/architecture/microservices-complete.md +735 -0
- package/architecture/resilience-and-disaster-patterns.md +37 -0
- package/architecture/service-governance.md +1198 -0
- package/architecture/system-architecture-deep-dive.md +37 -0
- package/backend/01-standards/analytics-and-growth.md +65 -0
- package/backend/01-standards/api-and-error-conventions.md +120 -0
- package/backend/01-standards/application-layering-and-packaging.md +160 -0
- package/backend/01-standards/auth-implementation.md +104 -0
- package/backend/01-standards/backend-framework-idioms.md +74 -0
- package/backend/01-standards/background-jobs-and-async.md +66 -0
- package/backend/01-standards/caching-strategies-complete.md +390 -0
- package/backend/01-standards/config-and-observability.md +77 -0
- package/backend/01-standards/data-modeling-and-persistence.md +94 -0
- package/backend/01-standards/django-complete.md +1765 -0
- package/backend/01-standards/email-and-notifications.md +64 -0
- package/backend/01-standards/fastapi-complete.md +925 -0
- package/backend/01-standards/file-upload-and-storage.md +66 -0
- package/backend/01-standards/graphql-api-complete.md +416 -0
- package/backend/01-standards/llm-application-standard.md +78 -0
- package/backend/01-standards/message-queue-patterns.md +379 -0
- package/backend/01-standards/microservices-and-distributed.md +78 -0
- package/backend/01-standards/nestjs-complete.md +2167 -0
- package/backend/01-standards/payment-integration.md +80 -0
- package/backend/01-standards/rate-limiting-complete.md +451 -0
- package/backend/01-standards/realtime-and-websocket.md +65 -0
- package/backend/01-standards/search-and-filtering.md +64 -0
- package/backend/01-standards/spring-boot-complete.md +445 -0
- package/backend/02-playbooks/api-design-playbook.md +718 -0
- package/backend/02-playbooks/email-send-playbook.md +130 -0
- package/backend/02-playbooks/file-upload-s3-playbook.md +153 -0
- package/backend/02-playbooks/typescript-enterprise-playbook.md +133 -0
- package/backend/02-playbooks/websocket-realtime-playbook.md +154 -0
- package/backend/03-checklists/api-launch-checklist.md +189 -0
- package/backend/04-antipatterns/backend-antipatterns.md +1051 -0
- package/blockchain/01-standards/blockchain-basics.md +557 -0
- package/blockchain/01-standards/smart-contract-development.md +1315 -0
- package/cicd/01-standards/deployment-and-delivery-standard.md +96 -0
- package/cicd/01-standards/github-actions-complete.md +473 -0
- package/cicd/01-standards/release-and-store-submission.md +75 -0
- package/cicd/02-playbooks/cicd-pipeline-playbook.md +144 -0
- package/cicd/02-playbooks/release-management-playbook.md +605 -0
- package/cicd/03-checklists/pipeline-security-checklist.md +168 -0
- package/cicd/04-antipatterns/cicd-antipatterns.md +589 -0
- package/cicd/05-cases/case-deployment-automation.md +221 -0
- package/cicd/05-cases/case-gitops-transformation.md +212 -0
- package/cicd/06-glossary/cicd-glossary.md +114 -0
- package/cicd/cicd-blueprint-deep-dive.md +38 -0
- package/cicd/release-readiness-gate.md +37 -0
- package/cloud-native/01-standards/container-security.md +741 -0
- package/cloud-native/01-standards/kubernetes-complete.md +812 -0
- package/cloud-native/02-playbooks/api-gateway-playbook.md +155 -0
- package/cloud-native/02-playbooks/gitops-with-argocd.md +760 -0
- package/cloud-native/02-playbooks/k8s-troubleshooting-playbook.md +1942 -0
- package/cloud-native/02-playbooks/message-queue-playbook.md +129 -0
- package/cloud-native/02-playbooks/multicloud-governance.md +726 -0
- package/cloud-native/02-playbooks/serverless-patterns.md +788 -0
- package/cloud-native/02-playbooks/service-mesh-playbook.md +612 -0
- package/cloud-native/02-playbooks/terraform-iac-playbook.md +143 -0
- package/cloud-native/03-checklists/container-security-checklist.md +431 -0
- package/cloud-native/03-checklists/k8s-production-readiness-checklist.md +460 -0
- package/cloud-native/04-antipatterns/container-antipatterns.md +660 -0
- package/cloud-native/04-antipatterns/k8s-antipatterns.md +743 -0
- package/cloud-native/05-cases/case-k8s-migration.md +478 -0
- package/cloud-native/05-cases/case-k8s-scaling.md +642 -0
- package/cloud-native/05-cases/case-k8s-security-incident.md +397 -0
- package/cloud-native/06-glossary/cloud-native-glossary.md +337 -0
- package/cross-platform/01-standards/cross-platform-frameworks.md +83 -0
- package/cross-platform/01-standards/platform-selection-and-architecture.md +77 -0
- package/data/01-standards/elasticsearch-complete.md +2098 -0
- package/data/01-standards/postgresql-complete.md +1613 -0
- package/data/01-standards/redis-complete.md +1527 -0
- package/data/02-playbooks/database-optimization-playbook.md +403 -0
- package/data/02-playbooks/elasticsearch-production-playbook.md +132 -0
- package/data/03-checklists/database-launch-checklist.md +187 -0
- package/data/04-antipatterns/database-antipatterns.md +873 -0
- package/data/05-cases/case-database-migration.md +310 -0
- package/data/06-glossary/database-glossary.md +440 -0
- package/data/data-governance-and-modeling-deep-dive.md +39 -0
- package/data-engineering/01-standards/airflow-complete.md +523 -0
- package/data-engineering/01-standards/kafka-complete.md +1521 -0
- package/data-engineering/02-playbooks/spark-etl-playbook.md +496 -0
- package/data-engineering/03-checklists/pipeline-launch-checklist.md +194 -0
- package/data-engineering/04-antipatterns/data-pipeline-antipatterns.md +684 -0
- package/data-engineering/05-cases/case-real-time-pipeline.md +355 -0
- package/data-engineering/06-glossary/data-engineering-glossary.md +429 -0
- package/database/01-standards/database-schema-standards.md +147 -0
- package/database/02-playbooks/postgresql-optimization-quick.md +52 -0
- package/database/02-playbooks/postgresql-performance-optimization.md +58 -0
- package/database/02-playbooks/postgresql-production-playbook.md +146 -0
- package/database/02-playbooks/redis-caching-playbook.md +117 -0
- package/database/03-checklists/database-review-checklist.md +50 -0
- package/database/04-antipatterns/database-antipatterns.md +112 -0
- package/design/01-standards/ui-design-system-complete.md +423 -0
- package/design/02-playbooks/design-handoff-playbook.md +254 -0
- package/design/02-playbooks/design-review-playbook.md +388 -0
- package/design/03-checklists/design-review-checklist.md +246 -0
- package/design/04-antipatterns/design-antipatterns.md +378 -0
- package/design/05-cases/case-design-system-adoption.md +328 -0
- package/design/06-glossary/design-glossary.md +329 -0
- package/design/ui-full-lifecycle-cross-platform-playbook.md +571 -0
- package/design/ux-system-deep-dive.md +38 -0
- package/design-systems/00-craft-rules.md +71 -0
- package/design-systems/aesthetic-families.md +43 -0
- package/design-systems/anti-ai-slop.md +162 -0
- package/design-systems/bold-geometric.md +120 -0
- package/design-systems/brutalist-bold.md +103 -0
- package/design-systems/editorial-clean.md +109 -0
- package/design-systems/glass-aurora.md +108 -0
- package/design-systems/modern-minimal.md +145 -0
- package/design-systems/premium-luxury.md +106 -0
- package/design-systems/product-type-design-map.md +48 -0
- package/design-systems/soft-warm.md +123 -0
- package/design-systems/tech-utility.md +113 -0
- package/desktop/01-standards/desktop-app-standard.md +72 -0
- package/desktop/01-standards/desktop-design.md +71 -0
- package/development/00-governance/document-template.md +41 -0
- package/development/01-standards/api-versioning-strategies.md +432 -0
- package/development/01-standards/authentication-patterns-complete.md +479 -0
- package/development/01-standards/css-architecture-complete.md +550 -0
- package/development/01-standards/database-migration-strategies.md +484 -0
- package/development/01-standards/elasticsearch-complete.md +347 -0
- package/development/01-standards/git-complete.md +371 -0
- package/development/01-standards/golang-complete.md +1565 -0
- package/development/01-standards/graphql-complete.md +298 -0
- package/development/01-standards/javascript-bundlers-complete.md +469 -0
- package/development/01-standards/javascript-typescript-complete.md +528 -0
- package/development/01-standards/jest-complete.md +275 -0
- package/development/01-standards/linux-complete.md +234 -0
- package/development/01-standards/logging-observability-complete.md +526 -0
- package/development/01-standards/microservices-communication.md +502 -0
- package/development/01-standards/mongodb-complete.md +406 -0
- package/development/01-standards/oauth2-complete.md +285 -0
- package/development/01-standards/performance-optimization-complete.md +289 -0
- package/development/01-standards/playwright-complete.md +247 -0
- package/development/01-standards/postgresql-complete.md +456 -0
- package/development/01-standards/pytest-complete.md +340 -0
- package/development/01-standards/python-async-programming.md +902 -0
- package/development/01-standards/python-complete.md +956 -0
- package/development/01-standards/python-decorators-complete.md +799 -0
- package/development/01-standards/python-design-patterns.md +2854 -0
- package/development/01-standards/python-packaging-distribution.md +420 -0
- package/development/01-standards/python-testing-strategies.md +607 -0
- package/development/01-standards/python-web-frameworks-comparison.md +471 -0
- package/development/01-standards/redis-complete.md +317 -0
- package/development/01-standards/rest-api-complete.md +316 -0
- package/development/01-standards/rust-complete.md +578 -0
- package/development/01-standards/typescript-advanced-types.md +1513 -0
- package/development/01-standards/web-security-complete.md +292 -0
- package/development/02-playbooks/api-design-playbook.md +810 -0
- package/development/02-playbooks/database-migration-playbook.md +580 -0
- package/development/02-playbooks/debugging-playbook.md +692 -0
- package/development/02-playbooks/feature-delivery-playbook.md +430 -0
- package/development/02-playbooks/incident-hotfix-playbook.md +387 -0
- package/development/02-playbooks/performance-optimization-playbook.md +531 -0
- package/development/02-playbooks/performance-tuning-playbook.md +652 -0
- package/development/02-playbooks/refactor-playbook.md +403 -0
- package/development/02-playbooks/release-playbook.md +469 -0
- package/development/03-checklists/architecture-review-checklist.md +168 -0
- package/development/03-checklists/data-migration-checklist.md +157 -0
- package/development/03-checklists/oncall-handover-checklist.md +173 -0
- package/development/03-checklists/pr-checklist.md +158 -0
- package/development/03-checklists/production-readiness-checklist.md +190 -0
- package/development/03-checklists/release-readiness-checklist.md +154 -0
- package/development/03-checklists/security-review-checklist.md +182 -0
- package/development/04-antipatterns/api-antipatterns.md +657 -0
- package/development/04-antipatterns/architecture-antipatterns.md +686 -0
- package/development/04-antipatterns/backend-antipatterns.md +648 -0
- package/development/04-antipatterns/cicd-antipatterns.md +540 -0
- package/development/04-antipatterns/code-smell-antipatterns.md +571 -0
- package/development/04-antipatterns/data-antipatterns.md +658 -0
- package/development/04-antipatterns/database-antipatterns.md +578 -0
- package/development/04-antipatterns/frontend-antipatterns.md +635 -0
- package/development/04-antipatterns/reliability-antipatterns.md +700 -0
- package/development/04-antipatterns/security-antipatterns.md +747 -0
- package/development/05-cases/case-api-version-migration.md +428 -0
- package/development/05-cases/case-authorization-hardening.md +383 -0
- package/development/05-cases/case-bluegreen-rollback.md +466 -0
- package/development/05-cases/case-cache-snowball-protection.md +485 -0
- package/development/05-cases/case-ci-cd-pipeline.md +544 -0
- package/development/05-cases/case-database-scaling.md +500 -0
- package/development/05-cases/case-db-hotspot-optimization.md +487 -0
- package/development/05-cases/case-incident-mttr-reduction.md +563 -0
- package/development/05-cases/case-microservice-migration.md +375 -0
- package/development/05-cases/case-performance-optimization.md +406 -0
- package/development/05-cases/case-security-incident-response.md +345 -0
- package/development/06-glossary/full-stack-glossary.md +166 -0
- package/development/09-maturity/quarterly-audit-template.md +35 -0
- package/development/11-ui-excellence/ui-aesthetic-system.md +41 -0
- package/development/11-ui-excellence/ui-engineering-excellence.md +435 -0
- package/development/12-scenarios/development-scenarios-guide.md +565 -0
- package/development/13-implementation-assets/implementation-toolkit.md +282 -0
- package/development/13-implementation-assets/knowledge-gates-execution.md +43 -0
- package/development/14-full-lifecycle/software-lifecycle-gates.md +511 -0
- package/development/15-lifecycle-templates/project-templates-collection.md +791 -0
- package/development/api-contract-and-versioning-guide.md +36 -0
- package/development/api-governance-complete.md +43 -0
- package/development/backend-engineering-complete.md +43 -0
- package/development/code-review-quality-complete.md +43 -0
- package/development/concurrency-reliability-complete.md +43 -0
- package/development/database-engineering-complete.md +43 -0
- package/development/engineering-effectiveness-complete.md +43 -0
- package/development/engineering-standards-deep-dive.md +38 -0
- package/development/frontend-engineering-complete.md +43 -0
- package/development/performance-capacity-complete.md +43 -0
- package/development/refactor-migration-complete.md +42 -0
- package/development/refactoring-and-techdebt-playbook.md +37 -0
- package/development/security-in-development-complete.md +43 -0
- package/devops/01-standards/cicd-pipeline-complete.md +262 -0
- package/devops/01-standards/docker-complete.md +1490 -0
- package/devops/01-standards/github-actions-complete.md +337 -0
- package/devops/01-standards/kubernetes-complete.md +638 -0
- package/devops/01-standards/terraform-complete.md +2117 -0
- package/devops/02-playbooks/docker-compose-playbook.md +233 -0
- package/devops/02-playbooks/docker-k8s-production-playbook.md +186 -0
- package/devops/02-playbooks/docker-production-playbook.md +952 -0
- package/edge-iot/01-standards/edge-iot-complete.md +473 -0
- package/experts/architect/api-design.md +178 -0
- package/experts/architect/methodology.md +124 -0
- package/experts/architect/security.md +75 -0
- package/experts/backend-lead/methodology.md +216 -0
- package/experts/devops/methodology.md +160 -0
- package/experts/frontend-lead/methodology.md +178 -0
- package/experts/product-manager/industry/ecommerce.md +43 -0
- package/experts/product-manager/industry/saas.md +40 -0
- package/experts/product-manager/methodology.md +97 -0
- package/experts/qa-lead/methodology.md +123 -0
- package/experts/qa-lead/test-strategy.md +128 -0
- package/experts/uiux-designer/methodology.md +125 -0
- package/frontend/01-standards/accessibility-complete.md +532 -0
- package/frontend/01-standards/accessibility-standard.md +74 -0
- package/frontend/01-standards/admin-dashboard-and-crud.md +72 -0
- package/frontend/01-standards/design-tokens-complete.md +444 -0
- package/frontend/01-standards/forms-and-validation.md +77 -0
- package/frontend/01-standards/frontend-architecture-and-layering.md +119 -0
- package/frontend/01-standards/i18n-and-localization.md +65 -0
- package/frontend/01-standards/nextjs-complete.md +451 -0
- package/frontend/01-standards/react-complete.md +713 -0
- package/frontend/01-standards/react-hooks-complete-guide.md +1100 -0
- package/frontend/01-standards/react-hooks-complete.md +1171 -0
- package/frontend/01-standards/seo-and-web-vitals.md +77 -0
- package/frontend/01-standards/state-management-complete.md +444 -0
- package/frontend/01-standards/vue-complete.md +499 -0
- package/frontend/01-standards/vue3-complete.md +2002 -0
- package/frontend/01-standards/web-framework-best-practices.md +64 -0
- package/frontend/01-standards/web-performance-complete.md +495 -0
- package/frontend/02-playbooks/accessibility-a11y-playbook.md +161 -0
- package/frontend/02-playbooks/frontend-performance-playbook.md +707 -0
- package/frontend/02-playbooks/i18n-internationalization-playbook.md +120 -0
- package/frontend/02-playbooks/performance-optimization-playbook.md +163 -0
- package/frontend/02-playbooks/react-nextjs-production-playbook.md +167 -0
- package/frontend/02-playbooks/react-state-management-playbook.md +173 -0
- package/frontend/03-checklists/component-quality-checklist.md +166 -0
- package/frontend/03-checklists/frontend-launch-checklist.md +299 -0
- package/frontend/04-antipatterns/frontend-antipatterns.md +886 -0
- package/frontend/05-cases/case-performance-optimization.md +274 -0
- package/harmony/01-standards/harmonyos-arkts-standard.md +75 -0
- package/harmony/01-standards/harmonyos-design.md +65 -0
- package/high-quality-engineering-playbook.md +54 -0
- package/incident/01-standards/incident-response-complete.md +303 -0
- package/incident/02-playbooks/chaos-engineering-playbook.md +883 -0
- package/incident/02-playbooks/postmortem-playbook.md +398 -0
- package/incident/03-checklists/incident-readiness-checklist.md +181 -0
- package/incident/04-antipatterns/incident-antipatterns.md +490 -0
- package/incident/05-cases/case-cascade-failure.md +176 -0
- package/incident/06-glossary/incident-glossary.md +114 -0
- package/incident/postmortem-and-response-deep-dive.md +39 -0
- package/industries/ecommerce/ecommerce-complete.md +631 -0
- package/industries/education/education-complete.md +555 -0
- package/industries/fintech/fintech-complete.md +501 -0
- package/industries/gaming/gaming-complete.md +587 -0
- package/industries/healthcare/healthcare-complete.md +452 -0
- package/low-code/01-standards/low-code-complete.md +944 -0
- package/miniprogram/01-standards/ai-common-mistakes.md +61 -0
- package/miniprogram/01-standards/miniprogram-custom-navbar-capsule.md +77 -0
- package/miniprogram/01-standards/miniprogram-design.md +61 -0
- package/miniprogram/01-standards/miniprogram-standard.md +81 -0
- package/mobile/01-standards/android-material-design.md +70 -0
- package/mobile/01-standards/flutter-complete.md +384 -0
- package/mobile/01-standards/ios-design-hig.md +78 -0
- package/mobile/01-standards/mobile-app-standard.md +85 -0
- package/mobile/01-standards/react-native-complete.md +352 -0
- package/mobile/02-playbooks/mobile-cross-platform-playbook.md +175 -0
- package/mobile/02-playbooks/mobile-performance.md +473 -0
- package/mobile/03-checklists/mobile-release-checklist.md +234 -0
- package/mobile/04-antipatterns/mobile-antipatterns.md +798 -0
- package/mobile/05-cases/case-app-performance.md +500 -0
- package/mobile/05-cases/case-app-startup-optimization.md +218 -0
- package/mobile/06-glossary/mobile-glossary.md +484 -0
- package/observability/01-standards/observability-standards.md +103 -0
- package/observability/02-playbooks/prometheus-grafana-playbook.md +135 -0
- package/observability/02-playbooks/structured-logging-playbook.md +73 -0
- package/observability/03-checklists/observability-checklist.md +54 -0
- package/observability/04-antipatterns/observability-antipatterns.md +106 -0
- package/operations/01-standards/prometheus-monitoring-complete.md +1578 -0
- package/operations/02-playbooks/capacity-planning-playbook.md +620 -0
- package/operations/03-checklists/production-launch-checklist.md +365 -0
- package/operations/04-antipatterns/operations-antipatterns.md +664 -0
- package/operations/05-cases/case-sre-practices.md +581 -0
- package/operations/06-glossary/operations-glossary.md +120 -0
- package/operations/aiops-anomaly-detection.md +758 -0
- package/operations/capacity-planning.md +1061 -0
- package/operations/chaos-engineering.md +659 -0
- package/operations/incident-command-system.md +38 -0
- package/operations/observability-complete.md +442 -0
- package/operations/slo-sli-playbook.md +517 -0
- package/operations/sre-operations-deep-dive.md +39 -0
- package/package.json +8 -0
- package/performance/01-standards/performance-and-scalability.md +80 -0
- package/performance/01-standards/performance-standards.md +156 -0
- package/performance/02-playbooks/query-optimization-playbook.md +103 -0
- package/performance/03-checklists/performance-checklist.md +56 -0
- package/performance/04-antipatterns/performance-antipatterns.md +146 -0
- package/product/01-standards/product-management-complete.md +285 -0
- package/product/02-playbooks/feature-launch-playbook.md +207 -0
- package/product/02-playbooks/user-research-playbook.md +532 -0
- package/product/03-checklists/feature-launch-checklist.md +275 -0
- package/product/04-antipatterns/product-antipatterns.md +355 -0
- package/product/05-cases/case-mvp-to-scale.md +384 -0
- package/product/06-glossary/product-glossary.md +462 -0
- package/product/feature-prioritization-framework.md +40 -0
- package/product/kpi-and-metric-tree.md +37 -0
- package/product/product-discovery-and-prd-deep-dive.md +41 -0
- package/quantum/01-standards/quantum-complete.md +1186 -0
- package/security/01-standards/api-security-complete.md +511 -0
- package/security/01-standards/container-runtime-security.md +574 -0
- package/security/01-standards/data-protection-gdpr.md +543 -0
- package/security/01-standards/owasp-top10-complete.md +1890 -0
- package/security/01-standards/secure-coding-baseline.md +90 -0
- package/security/01-standards/supply-chain-security.md +441 -0
- package/security/01-standards/web-security-checklist.md +108 -0
- package/security/01-standards/zero-trust-architecture.md +521 -0
- package/security/02-playbooks/auth-sso-playbook.md +166 -0
- package/security/02-playbooks/incident-response-security-playbook.md +588 -0
- package/security/02-playbooks/owasp-api-security-playbook.md +129 -0
- package/security/02-playbooks/payment-integration-playbook.md +119 -0
- package/security/02-playbooks/penetration-testing-playbook.md +517 -0
- package/security/03-checklists/security-audit-checklist.md +356 -0
- package/security/04-antipatterns/security-coding-antipatterns.md +580 -0
- package/security/05-cases/case-log4shell-incident.md +537 -0
- package/security/05-cases/case-major-breaches.md +468 -0
- package/security/06-glossary/security-glossary.md +212 -0
- package/security/compliance-automation.md +993 -0
- package/security/container-security.md +680 -0
- package/security/devsecops-complete.md +426 -0
- package/security/sast-dast-sca.md +775 -0
- package/security/secrets-management.md +594 -0
- package/security/security-architecture-deep-dive.md +37 -0
- package/security/threat-modeling-stride-playbook.md +40 -0
- package/seed-templates/auth-system.md +59 -0
- package/seed-templates/blog-content.md +94 -0
- package/seed-templates/dashboard.md +89 -0
- package/seed-templates/docs-site.md +73 -0
- package/seed-templates/e-commerce.md +50 -0
- package/seed-templates/saas-landing.md +92 -0
- package/seed-templates/settings-page.md +51 -0
- package/testing/01-standards/test-strategy-and-layering.md +83 -0
- package/testing/01-standards/testing-strategy-complete.md +422 -0
- package/testing/01-standards/unit-testing-best-practices.md +118 -0
- package/testing/02-playbooks/e2e-testing-playbook.md +988 -0
- package/testing/02-playbooks/testing-strategy-playbook.md +126 -0
- package/testing/03-checklists/test-strategy-checklist.md +208 -0
- package/testing/04-antipatterns/testing-antipatterns.md +718 -0
- package/testing/05-cases/case-testing-transformation.md +300 -0
- package/testing/06-glossary/testing-glossary.md +110 -0
- package/testing/risk-based-test-matrix.md +36 -0
- package/testing/testing-strategy-deep-dive.md +37 -0
|
@@ -0,0 +1,1565 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: golang-complete
|
|
3
|
+
title: Go 语言完整工程指南
|
|
4
|
+
domain: development
|
|
5
|
+
category: 01-standards
|
|
6
|
+
difficulty: intermediate
|
|
7
|
+
tags: [complete, development, golang, 并发模型, 性能优化, 接口设计, 标准库精选, 核心语法]
|
|
8
|
+
quality_score: 70
|
|
9
|
+
last_updated: 2026-06-15
|
|
10
|
+
---
|
|
11
|
+
# Go 语言完整工程指南
|
|
12
|
+
|
|
13
|
+
> UmaDev Knowledge Base | Domain: development | Type: standards
|
|
14
|
+
|
|
15
|
+
## 1. 概述
|
|
16
|
+
|
|
17
|
+
### 1.1 设计哲学
|
|
18
|
+
|
|
19
|
+
Go 由 Robert Griesemer、Rob Pike 和 Ken Thompson 在 Google 设计,核心哲学:
|
|
20
|
+
|
|
21
|
+
- **简洁胜于灵巧** — 语法关键字仅 25 个,没有继承、没有异常、没有宏
|
|
22
|
+
- **组合优于继承** — 通过嵌入(embedding)和接口实现多态
|
|
23
|
+
- **显式优于隐式** — 错误必须显式处理,类型转换必须显式声明
|
|
24
|
+
- **并发是一等公民** — goroutine + channel 是语言内建原语
|
|
25
|
+
- **工具链即标准** — gofmt / go vet / go test 是语言生态不可分割的部分
|
|
26
|
+
|
|
27
|
+
### 1.2 适用场景
|
|
28
|
+
|
|
29
|
+
| 场景 | 匹配度 | 说明 |
|
|
30
|
+
|------|--------|------|
|
|
31
|
+
| 云原生微服务 | 极高 | Kubernetes / Docker / Prometheus 均用 Go 编写 |
|
|
32
|
+
| CLI 工具 | 极高 | 单二进制、交叉编译、启动快 |
|
|
33
|
+
| 网络代理/中间件 | 极高 | 高并发 + 低延迟 |
|
|
34
|
+
| 数据管道 / ETL | 高 | goroutine 天然适合 fan-out/fan-in |
|
|
35
|
+
| Web API 服务 | 高 | 标准库 net/http 已足够生产使用 |
|
|
36
|
+
| 嵌入式 / GUI | 低 | 生态较弱 |
|
|
37
|
+
| 科学计算 / ML | 低 | 缺少成熟矩阵/张量库 |
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 2. 核心语法
|
|
42
|
+
|
|
43
|
+
### 2.1 类型系统
|
|
44
|
+
|
|
45
|
+
```go
|
|
46
|
+
// 基本类型
|
|
47
|
+
var (
|
|
48
|
+
b bool = true
|
|
49
|
+
i int = 42 // 平台相关位宽 (32/64)
|
|
50
|
+
i64 int64 = 1 << 40
|
|
51
|
+
f float64 = 3.14159
|
|
52
|
+
c complex128 = 3 + 4i
|
|
53
|
+
s string = "hello" // 不可变 UTF-8 字节序列
|
|
54
|
+
r rune = '中' // int32 别名,表示 Unicode 码点
|
|
55
|
+
bt byte = 0xFF // uint8 别名
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
// 零值规则:数值=0,布尔=false,字符串="",指针/切片/map/channel/interface=nil
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 2.2 结构体与方法
|
|
62
|
+
|
|
63
|
+
```go
|
|
64
|
+
type User struct {
|
|
65
|
+
ID int64 `json:"id" db:"id"`
|
|
66
|
+
Name string `json:"name" db:"name"`
|
|
67
|
+
Email string `json:"email" db:"email"`
|
|
68
|
+
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// 值接收者 — 不修改原始值
|
|
72
|
+
func (u User) DisplayName() string {
|
|
73
|
+
return fmt.Sprintf("%s <%s>", u.Name, u.Email)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// 指针接收者 — 可修改原始值,避免大结构体拷贝
|
|
77
|
+
func (u *User) SetEmail(email string) {
|
|
78
|
+
u.Email = email
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// 嵌入(组合)
|
|
82
|
+
type Admin struct {
|
|
83
|
+
User // 匿名嵌入,提升 User 的字段和方法
|
|
84
|
+
Permissions []string
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
admin := Admin{
|
|
88
|
+
User: User{ID: 1, Name: "root"},
|
|
89
|
+
Permissions: []string{"read", "write", "delete"},
|
|
90
|
+
}
|
|
91
|
+
fmt.Println(admin.DisplayName()) // 直接调用 User 的方法
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 2.3 切片、Map 与内部机制
|
|
95
|
+
|
|
96
|
+
```go
|
|
97
|
+
// 切片底层结构:{pointer, length, capacity}
|
|
98
|
+
s := make([]int, 0, 16) // len=0, cap=16
|
|
99
|
+
s = append(s, 1, 2, 3) // len=3, cap=16,无扩容
|
|
100
|
+
// 扩容策略(Go 1.18+):<256 翻倍;>=256 增长 25% + 192
|
|
101
|
+
|
|
102
|
+
// Map — 基于哈希表,无序
|
|
103
|
+
m := map[string]int{"a": 1, "b": 2}
|
|
104
|
+
// 检查 key 是否存在
|
|
105
|
+
if v, ok := m["c"]; ok {
|
|
106
|
+
fmt.Println(v)
|
|
107
|
+
}
|
|
108
|
+
// 注意:map 的零值是 nil,向 nil map 写入会 panic
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 2.4 包管理与模块
|
|
112
|
+
|
|
113
|
+
```go
|
|
114
|
+
// go.mod — 模块定义
|
|
115
|
+
module github.com/company/myservice
|
|
116
|
+
|
|
117
|
+
go 1.22
|
|
118
|
+
|
|
119
|
+
require (
|
|
120
|
+
github.com/gin-gonic/gin v1.9.1
|
|
121
|
+
google.golang.org/grpc v1.62.0
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
// 内部包约定:internal/ 目录只对父模块可见
|
|
125
|
+
// myservice/
|
|
126
|
+
// internal/
|
|
127
|
+
// auth/ <- 外部模块不可 import
|
|
128
|
+
// pkg/
|
|
129
|
+
// client/ <- 公开 API
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
go mod init github.com/company/myservice
|
|
134
|
+
go mod tidy # 同步依赖
|
|
135
|
+
go mod vendor # 生成 vendor/
|
|
136
|
+
go mod graph # 打印依赖图
|
|
137
|
+
go get -u ./... # 升级所有直接依赖
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## 3. 并发模型
|
|
143
|
+
|
|
144
|
+
### 3.1 Goroutine
|
|
145
|
+
|
|
146
|
+
```go
|
|
147
|
+
// goroutine 初始栈仅 2-8 KB,可轻松创建数十万个
|
|
148
|
+
go func() {
|
|
149
|
+
fmt.Println("running in goroutine")
|
|
150
|
+
}()
|
|
151
|
+
|
|
152
|
+
// 注意:main 退出时所有 goroutine 被强制终止
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### 3.2 Channel
|
|
156
|
+
|
|
157
|
+
```go
|
|
158
|
+
// 无缓冲 — 发送和接收同步阻塞
|
|
159
|
+
ch := make(chan int)
|
|
160
|
+
|
|
161
|
+
// 有缓冲 — 缓冲区满时发送阻塞,空时接收阻塞
|
|
162
|
+
ch := make(chan int, 100)
|
|
163
|
+
|
|
164
|
+
// 方向限定(函数签名中使用)
|
|
165
|
+
func producer(out chan<- int) { out <- 42 }
|
|
166
|
+
func consumer(in <-chan int) { v := <-in; _ = v }
|
|
167
|
+
|
|
168
|
+
// 关闭 channel
|
|
169
|
+
close(ch) // 只有发送方应该关闭;关闭后接收返回零值+false
|
|
170
|
+
|
|
171
|
+
// range 读取直到 channel 关闭
|
|
172
|
+
for v := range ch {
|
|
173
|
+
process(v)
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### 3.3 Select 多路复用
|
|
178
|
+
|
|
179
|
+
```go
|
|
180
|
+
select {
|
|
181
|
+
case msg := <-msgCh:
|
|
182
|
+
handle(msg)
|
|
183
|
+
case err := <-errCh:
|
|
184
|
+
log.Error(err)
|
|
185
|
+
case <-time.After(5 * time.Second):
|
|
186
|
+
log.Warn("timeout")
|
|
187
|
+
case <-ctx.Done():
|
|
188
|
+
return ctx.Err()
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// 非阻塞尝试
|
|
192
|
+
select {
|
|
193
|
+
case msg := <-ch:
|
|
194
|
+
handle(msg)
|
|
195
|
+
default:
|
|
196
|
+
// ch 为空,立即返回
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### 3.4 sync 包核心原语
|
|
201
|
+
|
|
202
|
+
```go
|
|
203
|
+
// WaitGroup — 等待一组 goroutine 完成
|
|
204
|
+
var wg sync.WaitGroup
|
|
205
|
+
for i := 0; i < 10; i++ {
|
|
206
|
+
wg.Add(1)
|
|
207
|
+
go func(id int) {
|
|
208
|
+
defer wg.Done()
|
|
209
|
+
process(id)
|
|
210
|
+
}(i)
|
|
211
|
+
}
|
|
212
|
+
wg.Wait()
|
|
213
|
+
|
|
214
|
+
// Mutex — 互斥锁
|
|
215
|
+
var mu sync.Mutex
|
|
216
|
+
mu.Lock()
|
|
217
|
+
sharedMap["key"] = "value"
|
|
218
|
+
mu.Unlock()
|
|
219
|
+
|
|
220
|
+
// RWMutex — 读写锁(多读单写)
|
|
221
|
+
var rwmu sync.RWMutex
|
|
222
|
+
rwmu.RLock() // 读锁,允许并发读
|
|
223
|
+
data := sharedMap["key"]
|
|
224
|
+
rwmu.RUnlock()
|
|
225
|
+
|
|
226
|
+
rwmu.Lock() // 写锁,独占
|
|
227
|
+
sharedMap["key"] = "newValue"
|
|
228
|
+
rwmu.Unlock()
|
|
229
|
+
|
|
230
|
+
// Once — 确保初始化只执行一次
|
|
231
|
+
var once sync.Once
|
|
232
|
+
var instance *Database
|
|
233
|
+
func GetDB() *Database {
|
|
234
|
+
once.Do(func() {
|
|
235
|
+
instance = connectDB()
|
|
236
|
+
})
|
|
237
|
+
return instance
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### 3.5 sync.Pool
|
|
242
|
+
|
|
243
|
+
```go
|
|
244
|
+
// sync.Pool — 减少频繁分配的 GC 压力
|
|
245
|
+
var bufPool = sync.Pool{
|
|
246
|
+
New: func() interface{} {
|
|
247
|
+
return new(bytes.Buffer)
|
|
248
|
+
},
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
func processRequest(data []byte) {
|
|
252
|
+
buf := bufPool.Get().(*bytes.Buffer)
|
|
253
|
+
defer func() {
|
|
254
|
+
buf.Reset()
|
|
255
|
+
bufPool.Put(buf)
|
|
256
|
+
}()
|
|
257
|
+
buf.Write(data)
|
|
258
|
+
// 使用 buf ...
|
|
259
|
+
}
|
|
260
|
+
// 注意:Pool 中对象可能在任意 GC 周期被回收,不要存储有状态对象
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### 3.6 errgroup
|
|
264
|
+
|
|
265
|
+
```go
|
|
266
|
+
import "golang.org/x/sync/errgroup"
|
|
267
|
+
|
|
268
|
+
func fetchAll(ctx context.Context, urls []string) ([]Response, error) {
|
|
269
|
+
g, ctx := errgroup.WithContext(ctx)
|
|
270
|
+
results := make([]Response, len(urls))
|
|
271
|
+
|
|
272
|
+
for i, url := range urls {
|
|
273
|
+
i, url := i, url // 捕获循环变量(Go <1.22 必需)
|
|
274
|
+
g.Go(func() error {
|
|
275
|
+
resp, err := fetch(ctx, url)
|
|
276
|
+
if err != nil {
|
|
277
|
+
return fmt.Errorf("fetch %s: %w", url, err)
|
|
278
|
+
}
|
|
279
|
+
results[i] = resp
|
|
280
|
+
return nil
|
|
281
|
+
})
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if err := g.Wait(); err != nil {
|
|
285
|
+
return nil, err // 返回第一个错误,并取消 ctx
|
|
286
|
+
}
|
|
287
|
+
return results, nil
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### 3.7 Context 传播与取消
|
|
292
|
+
|
|
293
|
+
```go
|
|
294
|
+
// 创建带取消的 context
|
|
295
|
+
ctx, cancel := context.WithCancel(context.Background())
|
|
296
|
+
defer cancel() // 确保资源释放
|
|
297
|
+
|
|
298
|
+
// 带超时
|
|
299
|
+
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
300
|
+
defer cancel()
|
|
301
|
+
|
|
302
|
+
// 带截止时间
|
|
303
|
+
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(1*time.Hour))
|
|
304
|
+
defer cancel()
|
|
305
|
+
|
|
306
|
+
// 传递值(仅用于请求范围的元数据,如 traceID / userID)
|
|
307
|
+
type ctxKey string
|
|
308
|
+
const traceIDKey ctxKey = "traceID"
|
|
309
|
+
|
|
310
|
+
ctx = context.WithValue(ctx, traceIDKey, "abc-123")
|
|
311
|
+
traceID := ctx.Value(traceIDKey).(string)
|
|
312
|
+
|
|
313
|
+
// 监听取消信号
|
|
314
|
+
func longRunningTask(ctx context.Context) error {
|
|
315
|
+
for {
|
|
316
|
+
select {
|
|
317
|
+
case <-ctx.Done():
|
|
318
|
+
return ctx.Err() // context.Canceled 或 context.DeadlineExceeded
|
|
319
|
+
default:
|
|
320
|
+
// 继续工作
|
|
321
|
+
doWork()
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Context 传播规则:
|
|
327
|
+
// 1. context.Background() 仅在 main / 顶层入口使用
|
|
328
|
+
// 2. 所有 I/O 和跨进程调用必须传递 ctx
|
|
329
|
+
// 3. 不要把 context 存到 struct 中,始终作为函数第一个参数
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## 4. 错误处理
|
|
335
|
+
|
|
336
|
+
### 4.1 error 接口
|
|
337
|
+
|
|
338
|
+
```go
|
|
339
|
+
// error 是内建接口
|
|
340
|
+
type error interface {
|
|
341
|
+
Error() string
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// 最简创建
|
|
345
|
+
err := errors.New("connection refused")
|
|
346
|
+
err := fmt.Errorf("invalid port: %d", port)
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### 4.2 自定义错误
|
|
350
|
+
|
|
351
|
+
```go
|
|
352
|
+
type NotFoundError struct {
|
|
353
|
+
Resource string
|
|
354
|
+
ID string
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
func (e *NotFoundError) Error() string {
|
|
358
|
+
return fmt.Sprintf("%s with id %s not found", e.Resource, e.ID)
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// 让错误实现 Unwrap() 支持错误链
|
|
362
|
+
type AppError struct {
|
|
363
|
+
Code int
|
|
364
|
+
Message string
|
|
365
|
+
Err error
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
func (e *AppError) Error() string { return e.Message }
|
|
369
|
+
func (e *AppError) Unwrap() error { return e.Err }
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### 4.3 Sentinel Errors
|
|
373
|
+
|
|
374
|
+
```go
|
|
375
|
+
// 定义包级别的哨兵错误
|
|
376
|
+
var (
|
|
377
|
+
ErrNotFound = errors.New("not found")
|
|
378
|
+
ErrUnauthorized = errors.New("unauthorized")
|
|
379
|
+
ErrConflict = errors.New("conflict")
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
// 使用哨兵错误
|
|
383
|
+
func GetUser(id string) (*User, error) {
|
|
384
|
+
user, err := repo.Find(id)
|
|
385
|
+
if err != nil {
|
|
386
|
+
if errors.Is(err, sql.ErrNoRows) {
|
|
387
|
+
return nil, fmt.Errorf("user %s: %w", id, ErrNotFound)
|
|
388
|
+
}
|
|
389
|
+
return nil, fmt.Errorf("query user: %w", err)
|
|
390
|
+
}
|
|
391
|
+
return user, nil
|
|
392
|
+
}
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### 4.4 errors.Is 与 errors.As
|
|
396
|
+
|
|
397
|
+
```go
|
|
398
|
+
// errors.Is — 沿错误链检查是否匹配某个值
|
|
399
|
+
if errors.Is(err, ErrNotFound) {
|
|
400
|
+
http.Error(w, "Not Found", 404)
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// errors.As — 沿错误链提取某个类型
|
|
404
|
+
var appErr *AppError
|
|
405
|
+
if errors.As(err, &appErr) {
|
|
406
|
+
log.Printf("code=%d msg=%s", appErr.Code, appErr.Message)
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// 错误包装与链(%w 动词)
|
|
410
|
+
original := errors.New("disk full")
|
|
411
|
+
wrapped := fmt.Errorf("save file: %w", original)
|
|
412
|
+
doubleWrapped := fmt.Errorf("process request: %w", wrapped)
|
|
413
|
+
|
|
414
|
+
errors.Is(doubleWrapped, original) // true
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### 4.5 错误处理最佳实践
|
|
418
|
+
|
|
419
|
+
```go
|
|
420
|
+
// 1. 添加上下文再返回
|
|
421
|
+
if err != nil {
|
|
422
|
+
return fmt.Errorf("createOrder(userID=%s): %w", userID, err)
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// 2. 只在顶层记录日志,底层只包装返回
|
|
426
|
+
// 3. 不要 log 后又 return err(会导致重复日志)
|
|
427
|
+
// 4. panic 仅用于不可恢复的程序错误(如 nil 解引用不应出现的不变量违反)
|
|
428
|
+
// 5. 库代码永远不要 panic,应返回 error
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
## 5. 接口设计
|
|
434
|
+
|
|
435
|
+
### 5.1 小接口原则
|
|
436
|
+
|
|
437
|
+
```go
|
|
438
|
+
// Go 标准库的经典小接口
|
|
439
|
+
type Reader interface { Read(p []byte) (n int, err error) }
|
|
440
|
+
type Writer interface { Write(p []byte) (n int, err error) }
|
|
441
|
+
type Closer interface { Close() error }
|
|
442
|
+
type Stringer interface { String() string }
|
|
443
|
+
|
|
444
|
+
// 组合小接口
|
|
445
|
+
type ReadWriteCloser interface {
|
|
446
|
+
Reader
|
|
447
|
+
Writer
|
|
448
|
+
Closer
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// 经验法则:接口方法数 <= 3;超过则考虑拆分
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
### 5.2 接口断言与 any
|
|
455
|
+
|
|
456
|
+
```go
|
|
457
|
+
// any 是 interface{} 的别名(Go 1.18+)
|
|
458
|
+
func printValue(v any) {
|
|
459
|
+
switch val := v.(type) {
|
|
460
|
+
case int:
|
|
461
|
+
fmt.Printf("int: %d\n", val)
|
|
462
|
+
case string:
|
|
463
|
+
fmt.Printf("string: %s\n", val)
|
|
464
|
+
case fmt.Stringer:
|
|
465
|
+
fmt.Printf("stringer: %s\n", val.String())
|
|
466
|
+
default:
|
|
467
|
+
fmt.Printf("unknown: %v\n", val)
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// 接口断言(带检查)
|
|
472
|
+
if s, ok := v.(fmt.Stringer); ok {
|
|
473
|
+
fmt.Println(s.String())
|
|
474
|
+
}
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
### 5.3 接口设计原则
|
|
478
|
+
|
|
479
|
+
```go
|
|
480
|
+
// 1. 在消费方定义接口,不在实现方
|
|
481
|
+
// bad: package storage 定义 Storage 接口并同时实现
|
|
482
|
+
// good: package handler 定义它需要的接口
|
|
483
|
+
|
|
484
|
+
type UserRepository interface { // 定义在 handler 包中
|
|
485
|
+
FindByID(ctx context.Context, id string) (*User, error)
|
|
486
|
+
Save(ctx context.Context, user *User) error
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// 2. 接受接口,返回结构体
|
|
490
|
+
func NewOrderService(repo OrderRepository, notifier Notifier) *OrderService {
|
|
491
|
+
return &OrderService{repo: repo, notifier: notifier}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// 3. 隐式接口满足 — 不需要 implements 关键字
|
|
495
|
+
// 编译期验证接口满足
|
|
496
|
+
var _ UserRepository = (*PostgresUserRepo)(nil)
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
---
|
|
500
|
+
|
|
501
|
+
## 6. 泛型(Go 1.18+)
|
|
502
|
+
|
|
503
|
+
### 6.1 类型参数与约束
|
|
504
|
+
|
|
505
|
+
```go
|
|
506
|
+
// 泛型函数
|
|
507
|
+
func Map[T any, U any](s []T, f func(T) U) []U {
|
|
508
|
+
result := make([]U, len(s))
|
|
509
|
+
for i, v := range s {
|
|
510
|
+
result[i] = f(v)
|
|
511
|
+
}
|
|
512
|
+
return result
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// 使用
|
|
516
|
+
names := Map(users, func(u User) string { return u.Name })
|
|
517
|
+
|
|
518
|
+
// 自定义约束
|
|
519
|
+
type Number interface {
|
|
520
|
+
~int | ~int8 | ~int16 | ~int32 | ~int64 |
|
|
521
|
+
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 |
|
|
522
|
+
~float32 | ~float64
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
func Sum[T Number](nums []T) T {
|
|
526
|
+
var total T
|
|
527
|
+
for _, n := range nums {
|
|
528
|
+
total += n
|
|
529
|
+
}
|
|
530
|
+
return total
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// ~ 波浪号表示包含底层类型,如 type Celsius float64 也能匹配 ~float64
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
### 6.2 泛型类型
|
|
537
|
+
|
|
538
|
+
```go
|
|
539
|
+
// 泛型数据结构
|
|
540
|
+
type Stack[T any] struct {
|
|
541
|
+
items []T
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
func (s *Stack[T]) Push(v T) { s.items = append(s.items, v) }
|
|
545
|
+
func (s *Stack[T]) Pop() (T, bool) {
|
|
546
|
+
if len(s.items) == 0 {
|
|
547
|
+
var zero T
|
|
548
|
+
return zero, false
|
|
549
|
+
}
|
|
550
|
+
v := s.items[len(s.items)-1]
|
|
551
|
+
s.items = s.items[:len(s.items)-1]
|
|
552
|
+
return v, true
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// 泛型约束接口
|
|
556
|
+
type Ordered interface {
|
|
557
|
+
~int | ~float64 | ~string
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
func Max[T Ordered](a, b T) T {
|
|
561
|
+
if a > b { return a }
|
|
562
|
+
return b
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// 标准库约束包
|
|
566
|
+
import "golang.org/x/exp/constraints" // 或 Go 1.21+ 的 cmp 包
|
|
567
|
+
import "cmp"
|
|
568
|
+
|
|
569
|
+
func Min[T cmp.Ordered](a, b T) T {
|
|
570
|
+
if a < b { return a }
|
|
571
|
+
return b
|
|
572
|
+
}
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
### 6.3 类型推断
|
|
576
|
+
|
|
577
|
+
```go
|
|
578
|
+
// Go 编译器通常可推断类型参数,无需显式指定
|
|
579
|
+
result := Map(numbers, double) // 推断 T=int, U=int
|
|
580
|
+
sorted := slices.SortFunc(users, func(a, b User) int {
|
|
581
|
+
return cmp.Compare(a.Name, b.Name)
|
|
582
|
+
})
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
---
|
|
586
|
+
|
|
587
|
+
## 7. 性能优化
|
|
588
|
+
|
|
589
|
+
### 7.1 内存分配优化
|
|
590
|
+
|
|
591
|
+
```go
|
|
592
|
+
// 1. 预分配切片
|
|
593
|
+
items := make([]Item, 0, expectedSize) // 避免反复扩容
|
|
594
|
+
|
|
595
|
+
// 2. 使用 strings.Builder 拼接字符串
|
|
596
|
+
var b strings.Builder
|
|
597
|
+
b.Grow(1024) // 预分配
|
|
598
|
+
for _, s := range parts {
|
|
599
|
+
b.WriteString(s)
|
|
600
|
+
}
|
|
601
|
+
result := b.String()
|
|
602
|
+
|
|
603
|
+
// 3. 避免不必要的 []byte <-> string 转换
|
|
604
|
+
// 4. 使用指针接收者避免大结构体拷贝
|
|
605
|
+
// 5. 对热路径考虑使用 sync.Pool
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
### 7.2 逃逸分析
|
|
609
|
+
|
|
610
|
+
```go
|
|
611
|
+
// 变量是否分配到堆由编译器逃逸分析决定
|
|
612
|
+
// 查看逃逸分析结果:
|
|
613
|
+
// go build -gcflags="-m" ./...
|
|
614
|
+
|
|
615
|
+
// 导致逃逸的常见原因:
|
|
616
|
+
// 1. 返回局部变量的指针
|
|
617
|
+
func newUser() *User { u := User{}; return &u } // u 逃逸到堆
|
|
618
|
+
|
|
619
|
+
// 2. 赋值给接口类型
|
|
620
|
+
var w io.Writer = os.Stdout // 值可能逃逸
|
|
621
|
+
|
|
622
|
+
// 3. 闭包捕获的变量
|
|
623
|
+
// 4. 切片 append 触发扩容后数据迁移
|
|
624
|
+
|
|
625
|
+
// 减少逃逸的技巧:
|
|
626
|
+
// - 使用值类型而非指针(小结构体 <= 64 bytes)
|
|
627
|
+
// - 避免不必要的接口装箱
|
|
628
|
+
// - 预分配 buffer 并通过参数传入而非函数内创建
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
### 7.3 pprof 性能分析
|
|
632
|
+
|
|
633
|
+
```go
|
|
634
|
+
import (
|
|
635
|
+
"net/http"
|
|
636
|
+
_ "net/http/pprof" // 注册 pprof 端点
|
|
637
|
+
)
|
|
638
|
+
|
|
639
|
+
func main() {
|
|
640
|
+
// 生产服务中启用 pprof(仅内网)
|
|
641
|
+
go func() {
|
|
642
|
+
log.Println(http.ListenAndServe("localhost:6060", nil))
|
|
643
|
+
}()
|
|
644
|
+
}
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
```bash
|
|
648
|
+
# CPU 分析(采集 30 秒)
|
|
649
|
+
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
|
|
650
|
+
|
|
651
|
+
# 内存分析
|
|
652
|
+
go tool pprof http://localhost:6060/debug/pprof/heap
|
|
653
|
+
|
|
654
|
+
# Goroutine 分析(排查泄漏)
|
|
655
|
+
go tool pprof http://localhost:6060/debug/pprof/goroutine
|
|
656
|
+
|
|
657
|
+
# 常用交互命令
|
|
658
|
+
# top10 — 最耗资源的 10 个函数
|
|
659
|
+
# list funcName — 逐行分析
|
|
660
|
+
# web — 生成火焰图(需安装 graphviz)
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
### 7.4 trace 工具
|
|
664
|
+
|
|
665
|
+
```bash
|
|
666
|
+
# 收集 trace 数据
|
|
667
|
+
curl -o trace.out http://localhost:6060/debug/pprof/trace?seconds=5
|
|
668
|
+
go tool trace trace.out
|
|
669
|
+
|
|
670
|
+
# trace 能可视化:goroutine 调度、GC 暂停、网络/系统调用阻塞
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
### 7.5 Benchmark 基准测试
|
|
674
|
+
|
|
675
|
+
```go
|
|
676
|
+
func BenchmarkJSONMarshal(b *testing.B) {
|
|
677
|
+
user := User{ID: 1, Name: "test", Email: "test@example.com"}
|
|
678
|
+
b.ResetTimer()
|
|
679
|
+
b.ReportAllocs() // 报告内存分配次数
|
|
680
|
+
|
|
681
|
+
for i := 0; i < b.N; i++ {
|
|
682
|
+
json.Marshal(user)
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
// 子基准测试
|
|
687
|
+
func BenchmarkHash(b *testing.B) {
|
|
688
|
+
sizes := []int{64, 256, 1024, 4096}
|
|
689
|
+
for _, size := range sizes {
|
|
690
|
+
b.Run(fmt.Sprintf("size=%d", size), func(b *testing.B) {
|
|
691
|
+
data := make([]byte, size)
|
|
692
|
+
b.ResetTimer()
|
|
693
|
+
for i := 0; i < b.N; i++ {
|
|
694
|
+
sha256.Sum256(data)
|
|
695
|
+
}
|
|
696
|
+
})
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
```bash
|
|
702
|
+
go test -bench=. -benchmem ./...
|
|
703
|
+
go test -bench=BenchmarkHash -count=5 -benchtime=3s ./...
|
|
704
|
+
|
|
705
|
+
# 对比两次结果
|
|
706
|
+
go install golang.org/x/perf/cmd/benchstat@latest
|
|
707
|
+
benchstat old.txt new.txt
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
---
|
|
711
|
+
|
|
712
|
+
## 8. 标准库精选
|
|
713
|
+
|
|
714
|
+
### 8.1 net/http
|
|
715
|
+
|
|
716
|
+
```go
|
|
717
|
+
// 生产级 HTTP 服务器
|
|
718
|
+
srv := &http.Server{
|
|
719
|
+
Addr: ":8080",
|
|
720
|
+
Handler: mux,
|
|
721
|
+
ReadTimeout: 5 * time.Second,
|
|
722
|
+
WriteTimeout: 10 * time.Second,
|
|
723
|
+
IdleTimeout: 120 * time.Second,
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
// 中间件模式
|
|
727
|
+
func loggingMiddleware(next http.Handler) http.Handler {
|
|
728
|
+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
729
|
+
start := time.Now()
|
|
730
|
+
next.ServeHTTP(w, r)
|
|
731
|
+
log.Printf("%s %s %v", r.Method, r.URL.Path, time.Since(start))
|
|
732
|
+
})
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
// Go 1.22+ 路由增强
|
|
736
|
+
mux := http.NewServeMux()
|
|
737
|
+
mux.HandleFunc("GET /users/{id}", getUser)
|
|
738
|
+
mux.HandleFunc("POST /users", createUser)
|
|
739
|
+
mux.HandleFunc("DELETE /users/{id}", deleteUser)
|
|
740
|
+
|
|
741
|
+
func getUser(w http.ResponseWriter, r *http.Request) {
|
|
742
|
+
id := r.PathValue("id")
|
|
743
|
+
// ...
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
// 生产级 HTTP 客户端(设置超时!)
|
|
747
|
+
client := &http.Client{
|
|
748
|
+
Timeout: 10 * time.Second,
|
|
749
|
+
Transport: &http.Transport{
|
|
750
|
+
MaxIdleConns: 100,
|
|
751
|
+
MaxIdleConnsPerHost: 10,
|
|
752
|
+
IdleConnTimeout: 90 * time.Second,
|
|
753
|
+
},
|
|
754
|
+
}
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
### 8.2 encoding/json
|
|
758
|
+
|
|
759
|
+
```go
|
|
760
|
+
type APIResponse struct {
|
|
761
|
+
Code int `json:"code"`
|
|
762
|
+
Message string `json:"message"`
|
|
763
|
+
Data json.RawMessage `json:"data,omitempty"` // 延迟解析
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
// 自定义 JSON 序列化
|
|
767
|
+
type Timestamp time.Time
|
|
768
|
+
|
|
769
|
+
func (t Timestamp) MarshalJSON() ([]byte, error) {
|
|
770
|
+
return json.Marshal(time.Time(t).Unix())
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
func (t *Timestamp) UnmarshalJSON(data []byte) error {
|
|
774
|
+
var unix int64
|
|
775
|
+
if err := json.Unmarshal(data, &unix); err != nil {
|
|
776
|
+
return err
|
|
777
|
+
}
|
|
778
|
+
*t = Timestamp(time.Unix(unix, 0))
|
|
779
|
+
return nil
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
// 流式解析大 JSON
|
|
783
|
+
decoder := json.NewDecoder(r.Body)
|
|
784
|
+
decoder.DisallowUnknownFields() // 严格模式
|
|
785
|
+
if err := decoder.Decode(&req); err != nil {
|
|
786
|
+
http.Error(w, "invalid json", 400)
|
|
787
|
+
return
|
|
788
|
+
}
|
|
789
|
+
```
|
|
790
|
+
|
|
791
|
+
### 8.3 database/sql
|
|
792
|
+
|
|
793
|
+
```go
|
|
794
|
+
import (
|
|
795
|
+
"database/sql"
|
|
796
|
+
_ "github.com/lib/pq" // PostgreSQL 驱动
|
|
797
|
+
)
|
|
798
|
+
|
|
799
|
+
// 连接池配置
|
|
800
|
+
db, err := sql.Open("postgres", dsn)
|
|
801
|
+
if err != nil {
|
|
802
|
+
log.Fatal(err)
|
|
803
|
+
}
|
|
804
|
+
db.SetMaxOpenConns(25)
|
|
805
|
+
db.SetMaxIdleConns(10)
|
|
806
|
+
db.SetConnMaxLifetime(5 * time.Minute)
|
|
807
|
+
db.SetConnMaxIdleTime(1 * time.Minute)
|
|
808
|
+
|
|
809
|
+
// 带 context 查询
|
|
810
|
+
func (r *UserRepo) FindByID(ctx context.Context, id int64) (*User, error) {
|
|
811
|
+
var u User
|
|
812
|
+
err := r.db.QueryRowContext(ctx,
|
|
813
|
+
"SELECT id, name, email FROM users WHERE id = $1", id,
|
|
814
|
+
).Scan(&u.ID, &u.Name, &u.Email)
|
|
815
|
+
if err == sql.ErrNoRows {
|
|
816
|
+
return nil, ErrNotFound
|
|
817
|
+
}
|
|
818
|
+
return &u, err
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
// 事务
|
|
822
|
+
func (r *OrderRepo) CreateOrder(ctx context.Context, order *Order) error {
|
|
823
|
+
tx, err := r.db.BeginTx(ctx, nil)
|
|
824
|
+
if err != nil {
|
|
825
|
+
return err
|
|
826
|
+
}
|
|
827
|
+
defer tx.Rollback() // 如果 Commit 已调用,Rollback 为 no-op
|
|
828
|
+
|
|
829
|
+
_, err = tx.ExecContext(ctx, "INSERT INTO orders ...")
|
|
830
|
+
if err != nil {
|
|
831
|
+
return err
|
|
832
|
+
}
|
|
833
|
+
_, err = tx.ExecContext(ctx, "UPDATE inventory ...")
|
|
834
|
+
if err != nil {
|
|
835
|
+
return err
|
|
836
|
+
}
|
|
837
|
+
return tx.Commit()
|
|
838
|
+
}
|
|
839
|
+
```
|
|
840
|
+
|
|
841
|
+
### 8.4 context 包(详见 3.7 节)
|
|
842
|
+
|
|
843
|
+
### 8.5 io 包
|
|
844
|
+
|
|
845
|
+
```go
|
|
846
|
+
// io.Reader / io.Writer 是 Go 最重要的抽象
|
|
847
|
+
// 组合 Reader
|
|
848
|
+
r := io.LimitReader(resp.Body, 1<<20) // 限制读取 1MB
|
|
849
|
+
r = io.TeeReader(r, &buf) // 同时写入 buf
|
|
850
|
+
|
|
851
|
+
// 高效复制
|
|
852
|
+
written, err := io.Copy(dst, src) // 自动使用 buffer
|
|
853
|
+
written, err := io.CopyN(dst, src, 1024) // 复制 N 字节
|
|
854
|
+
written, err := io.CopyBuffer(dst, src, buf) // 使用指定 buffer
|
|
855
|
+
|
|
856
|
+
// ReadAll(注意内存,生产中优先用流式处理)
|
|
857
|
+
data, err := io.ReadAll(resp.Body)
|
|
858
|
+
```
|
|
859
|
+
|
|
860
|
+
---
|
|
861
|
+
|
|
862
|
+
## 9. Web 框架对比
|
|
863
|
+
|
|
864
|
+
### 9.1 Gin vs Fiber vs Echo
|
|
865
|
+
|
|
866
|
+
| 特性 | Gin | Fiber | Echo |
|
|
867
|
+
|------|-----|-------|------|
|
|
868
|
+
| 底层 | net/http | fasthttp | net/http |
|
|
869
|
+
| 性能 | 高 | 极高 | 高 |
|
|
870
|
+
| 生态 | 最大 | 增长中 | 成熟 |
|
|
871
|
+
| 中间件 | 丰富 | 丰富 | 丰富 |
|
|
872
|
+
| 路由 | radix tree | 前缀树 | radix tree |
|
|
873
|
+
| 学习成本 | 低 | 低(类Express) | 低 |
|
|
874
|
+
| net/http兼容 | 完全 | 不兼容 | 完全 |
|
|
875
|
+
| 推荐场景 | 通用首选 | 极致性能 | 企业API |
|
|
876
|
+
|
|
877
|
+
### 9.2 Gin 示例
|
|
878
|
+
|
|
879
|
+
```go
|
|
880
|
+
r := gin.Default() // 包含 Logger + Recovery 中间件
|
|
881
|
+
|
|
882
|
+
// 路由组 + 中间件
|
|
883
|
+
api := r.Group("/api/v1", authMiddleware())
|
|
884
|
+
{
|
|
885
|
+
api.GET("/users", listUsers)
|
|
886
|
+
api.GET("/users/:id", getUser)
|
|
887
|
+
api.POST("/users", createUser)
|
|
888
|
+
api.PUT("/users/:id", updateUser)
|
|
889
|
+
api.DELETE("/users/:id", deleteUser)
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
func getUser(c *gin.Context) {
|
|
893
|
+
id := c.Param("id")
|
|
894
|
+
user, err := userService.FindByID(c.Request.Context(), id)
|
|
895
|
+
if err != nil {
|
|
896
|
+
if errors.Is(err, ErrNotFound) {
|
|
897
|
+
c.JSON(404, gin.H{"error": "user not found"})
|
|
898
|
+
return
|
|
899
|
+
}
|
|
900
|
+
c.JSON(500, gin.H{"error": "internal error"})
|
|
901
|
+
return
|
|
902
|
+
}
|
|
903
|
+
c.JSON(200, user)
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
// 参数绑定与验证
|
|
907
|
+
type CreateUserRequest struct {
|
|
908
|
+
Name string `json:"name" binding:"required,min=2,max=50"`
|
|
909
|
+
Email string `json:"email" binding:"required,email"`
|
|
910
|
+
Age int `json:"age" binding:"gte=0,lte=150"`
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
func createUser(c *gin.Context) {
|
|
914
|
+
var req CreateUserRequest
|
|
915
|
+
if err := c.ShouldBindJSON(&req); err != nil {
|
|
916
|
+
c.JSON(400, gin.H{"error": err.Error()})
|
|
917
|
+
return
|
|
918
|
+
}
|
|
919
|
+
// ...
|
|
920
|
+
}
|
|
921
|
+
```
|
|
922
|
+
|
|
923
|
+
---
|
|
924
|
+
|
|
925
|
+
## 10. 微服务开发
|
|
926
|
+
|
|
927
|
+
### 10.1 gRPC + Protobuf
|
|
928
|
+
|
|
929
|
+
```protobuf
|
|
930
|
+
// proto/user.proto
|
|
931
|
+
syntax = "proto3";
|
|
932
|
+
package user;
|
|
933
|
+
option go_package = "github.com/company/myservice/proto/user";
|
|
934
|
+
|
|
935
|
+
service UserService {
|
|
936
|
+
rpc GetUser(GetUserRequest) returns (UserResponse);
|
|
937
|
+
rpc ListUsers(ListUsersRequest) returns (stream UserResponse);
|
|
938
|
+
rpc CreateUser(CreateUserRequest) returns (UserResponse);
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
message GetUserRequest {
|
|
942
|
+
string id = 1;
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
message UserResponse {
|
|
946
|
+
string id = 1;
|
|
947
|
+
string name = 2;
|
|
948
|
+
string email = 3;
|
|
949
|
+
int64 created_at = 4;
|
|
950
|
+
}
|
|
951
|
+
```
|
|
952
|
+
|
|
953
|
+
```go
|
|
954
|
+
// 服务端实现
|
|
955
|
+
type userServer struct {
|
|
956
|
+
pb.UnimplementedUserServiceServer
|
|
957
|
+
repo UserRepository
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
func (s *userServer) GetUser(ctx context.Context, req *pb.GetUserRequest) (*pb.UserResponse, error) {
|
|
961
|
+
user, err := s.repo.FindByID(ctx, req.Id)
|
|
962
|
+
if err != nil {
|
|
963
|
+
return nil, status.Errorf(codes.NotFound, "user not found: %v", err)
|
|
964
|
+
}
|
|
965
|
+
return &pb.UserResponse{
|
|
966
|
+
Id: user.ID,
|
|
967
|
+
Name: user.Name,
|
|
968
|
+
Email: user.Email,
|
|
969
|
+
}, nil
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
// 启动 gRPC 服务器
|
|
973
|
+
lis, _ := net.Listen("tcp", ":50051")
|
|
974
|
+
grpcServer := grpc.NewServer(
|
|
975
|
+
grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
|
|
976
|
+
grpc_recovery.UnaryServerInterceptor(),
|
|
977
|
+
grpc_zap.UnaryServerInterceptor(logger),
|
|
978
|
+
)),
|
|
979
|
+
)
|
|
980
|
+
pb.RegisterUserServiceServer(grpcServer, &userServer{repo: repo})
|
|
981
|
+
grpcServer.Serve(lis)
|
|
982
|
+
```
|
|
983
|
+
|
|
984
|
+
### 10.2 服务发现与断路器
|
|
985
|
+
|
|
986
|
+
```go
|
|
987
|
+
// 使用 go-kit 或 hashicorp/consul 进行服务发现
|
|
988
|
+
|
|
989
|
+
// 断路器 — sony/gobreaker
|
|
990
|
+
cb := gobreaker.NewCircuitBreaker(gobreaker.Settings{
|
|
991
|
+
Name: "userService",
|
|
992
|
+
MaxRequests: 3, // 半开状态最大请求数
|
|
993
|
+
Interval: 10 * time.Second, // 统计窗口
|
|
994
|
+
Timeout: 30 * time.Second, // 开路到半开的等待时间
|
|
995
|
+
ReadyToTrip: func(counts gobreaker.Counts) bool {
|
|
996
|
+
return counts.ConsecutiveFailures > 5
|
|
997
|
+
},
|
|
998
|
+
OnStateChange: func(name string, from, to gobreaker.State) {
|
|
999
|
+
log.Printf("breaker %s: %s -> %s", name, from, to)
|
|
1000
|
+
},
|
|
1001
|
+
})
|
|
1002
|
+
|
|
1003
|
+
result, err := cb.Execute(func() (interface{}, error) {
|
|
1004
|
+
return client.GetUser(ctx, userID)
|
|
1005
|
+
})
|
|
1006
|
+
```
|
|
1007
|
+
|
|
1008
|
+
### 10.3 健康检查与优雅退出
|
|
1009
|
+
|
|
1010
|
+
```go
|
|
1011
|
+
func main() {
|
|
1012
|
+
srv := &http.Server{Addr: ":8080", Handler: mux}
|
|
1013
|
+
|
|
1014
|
+
// 启动
|
|
1015
|
+
go func() {
|
|
1016
|
+
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
|
|
1017
|
+
log.Fatalf("listen: %v", err)
|
|
1018
|
+
}
|
|
1019
|
+
}()
|
|
1020
|
+
|
|
1021
|
+
// 等待中断信号
|
|
1022
|
+
quit := make(chan os.Signal, 1)
|
|
1023
|
+
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
|
1024
|
+
<-quit
|
|
1025
|
+
log.Println("shutting down...")
|
|
1026
|
+
|
|
1027
|
+
// 优雅退出,给 30 秒处理剩余请求
|
|
1028
|
+
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
1029
|
+
defer cancel()
|
|
1030
|
+
if err := srv.Shutdown(ctx); err != nil {
|
|
1031
|
+
log.Fatalf("shutdown: %v", err)
|
|
1032
|
+
}
|
|
1033
|
+
log.Println("server stopped")
|
|
1034
|
+
}
|
|
1035
|
+
```
|
|
1036
|
+
|
|
1037
|
+
---
|
|
1038
|
+
|
|
1039
|
+
## 11. 测试
|
|
1040
|
+
|
|
1041
|
+
### 11.1 testing 包基础
|
|
1042
|
+
|
|
1043
|
+
```go
|
|
1044
|
+
func TestUserService_Create(t *testing.T) {
|
|
1045
|
+
t.Parallel() // 标记可并行执行
|
|
1046
|
+
|
|
1047
|
+
svc := NewUserService(mockRepo)
|
|
1048
|
+
user, err := svc.Create(context.Background(), "Alice", "alice@example.com")
|
|
1049
|
+
|
|
1050
|
+
if err != nil {
|
|
1051
|
+
t.Fatalf("unexpected error: %v", err)
|
|
1052
|
+
}
|
|
1053
|
+
if user.Name != "Alice" {
|
|
1054
|
+
t.Errorf("got name=%q, want %q", user.Name, "Alice")
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
```
|
|
1058
|
+
|
|
1059
|
+
### 11.2 Table-Driven Tests
|
|
1060
|
+
|
|
1061
|
+
```go
|
|
1062
|
+
func TestValidateEmail(t *testing.T) {
|
|
1063
|
+
tests := []struct {
|
|
1064
|
+
name string
|
|
1065
|
+
email string
|
|
1066
|
+
wantErr bool
|
|
1067
|
+
}{
|
|
1068
|
+
{"valid email", "user@example.com", false},
|
|
1069
|
+
{"no at sign", "userexample.com", true},
|
|
1070
|
+
{"no domain", "user@", true},
|
|
1071
|
+
{"empty", "", true},
|
|
1072
|
+
{"unicode local", "用户@example.com", false},
|
|
1073
|
+
{"multiple at", "a@b@c.com", true},
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
for _, tt := range tests {
|
|
1077
|
+
t.Run(tt.name, func(t *testing.T) {
|
|
1078
|
+
t.Parallel()
|
|
1079
|
+
err := ValidateEmail(tt.email)
|
|
1080
|
+
if (err != nil) != tt.wantErr {
|
|
1081
|
+
t.Errorf("ValidateEmail(%q) error=%v, wantErr=%v", tt.email, err, tt.wantErr)
|
|
1082
|
+
}
|
|
1083
|
+
})
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
```
|
|
1087
|
+
|
|
1088
|
+
### 11.3 httptest
|
|
1089
|
+
|
|
1090
|
+
```go
|
|
1091
|
+
func TestGetUserHandler(t *testing.T) {
|
|
1092
|
+
// 创建测试服务器
|
|
1093
|
+
handler := NewRouter(mockService)
|
|
1094
|
+
ts := httptest.NewServer(handler)
|
|
1095
|
+
defer ts.Close()
|
|
1096
|
+
|
|
1097
|
+
resp, err := http.Get(ts.URL + "/api/users/123")
|
|
1098
|
+
if err != nil {
|
|
1099
|
+
t.Fatal(err)
|
|
1100
|
+
}
|
|
1101
|
+
defer resp.Body.Close()
|
|
1102
|
+
|
|
1103
|
+
if resp.StatusCode != 200 {
|
|
1104
|
+
t.Errorf("status=%d, want 200", resp.StatusCode)
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
var user User
|
|
1108
|
+
json.NewDecoder(resp.Body).Decode(&user)
|
|
1109
|
+
if user.ID != "123" {
|
|
1110
|
+
t.Errorf("got id=%s, want 123", user.ID)
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
// 测试单个 handler(不需要完整服务器)
|
|
1115
|
+
func TestCreateUserHandler(t *testing.T) {
|
|
1116
|
+
body := strings.NewReader(`{"name":"Alice","email":"alice@test.com"}`)
|
|
1117
|
+
req := httptest.NewRequest("POST", "/api/users", body)
|
|
1118
|
+
req.Header.Set("Content-Type", "application/json")
|
|
1119
|
+
w := httptest.NewRecorder()
|
|
1120
|
+
|
|
1121
|
+
createUserHandler(w, req)
|
|
1122
|
+
|
|
1123
|
+
if w.Code != 201 {
|
|
1124
|
+
t.Errorf("status=%d, want 201", w.Code)
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
```
|
|
1128
|
+
|
|
1129
|
+
### 11.4 testify 与 gomock
|
|
1130
|
+
|
|
1131
|
+
```go
|
|
1132
|
+
// testify — 断言库
|
|
1133
|
+
import "github.com/stretchr/testify/assert"
|
|
1134
|
+
|
|
1135
|
+
func TestOrder(t *testing.T) {
|
|
1136
|
+
order, err := createOrder(ctx, items)
|
|
1137
|
+
assert.NoError(t, err)
|
|
1138
|
+
assert.Equal(t, "pending", order.Status)
|
|
1139
|
+
assert.Len(t, order.Items, 3)
|
|
1140
|
+
assert.Contains(t, order.Items, expectedItem)
|
|
1141
|
+
assert.WithinDuration(t, time.Now(), order.CreatedAt, time.Second)
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
// gomock — 接口 Mock
|
|
1145
|
+
//go:generate mockgen -source=repository.go -destination=mock_repository.go -package=service
|
|
1146
|
+
|
|
1147
|
+
func TestUserService_Get(t *testing.T) {
|
|
1148
|
+
ctrl := gomock.NewController(t)
|
|
1149
|
+
mockRepo := NewMockUserRepository(ctrl)
|
|
1150
|
+
|
|
1151
|
+
mockRepo.EXPECT().
|
|
1152
|
+
FindByID(gomock.Any(), "user-1").
|
|
1153
|
+
Return(&User{ID: "user-1", Name: "Alice"}, nil)
|
|
1154
|
+
|
|
1155
|
+
svc := NewUserService(mockRepo)
|
|
1156
|
+
user, err := svc.Get(context.Background(), "user-1")
|
|
1157
|
+
assert.NoError(t, err)
|
|
1158
|
+
assert.Equal(t, "Alice", user.Name)
|
|
1159
|
+
}
|
|
1160
|
+
```
|
|
1161
|
+
|
|
1162
|
+
---
|
|
1163
|
+
|
|
1164
|
+
## 12. 工具链
|
|
1165
|
+
|
|
1166
|
+
### 12.1 go mod
|
|
1167
|
+
|
|
1168
|
+
```bash
|
|
1169
|
+
go mod init github.com/company/project # 初始化模块
|
|
1170
|
+
go mod tidy # 同步依赖(移除无用+补充缺失)
|
|
1171
|
+
go mod vendor # 生成 vendor/
|
|
1172
|
+
go mod graph # 打印依赖图
|
|
1173
|
+
go mod why github.com/some/dep # 查看依赖为何被引入
|
|
1174
|
+
go mod edit -replace old=new@v1.0.0 # 替换依赖
|
|
1175
|
+
go list -m -json all # JSON 格式列出所有依赖
|
|
1176
|
+
```
|
|
1177
|
+
|
|
1178
|
+
### 12.2 go vet 与 golangci-lint
|
|
1179
|
+
|
|
1180
|
+
```bash
|
|
1181
|
+
# go vet — 内建静态分析
|
|
1182
|
+
go vet ./...
|
|
1183
|
+
|
|
1184
|
+
# golangci-lint — 聚合 100+ linter
|
|
1185
|
+
# .golangci.yml 推荐配置
|
|
1186
|
+
```
|
|
1187
|
+
|
|
1188
|
+
```yaml
|
|
1189
|
+
# .golangci.yml
|
|
1190
|
+
run:
|
|
1191
|
+
timeout: 5m
|
|
1192
|
+
|
|
1193
|
+
linters:
|
|
1194
|
+
enable:
|
|
1195
|
+
- errcheck # 检查未处理的错误
|
|
1196
|
+
- govet # 内建 vet 检查
|
|
1197
|
+
- staticcheck # 高级静态分析
|
|
1198
|
+
- unused # 未使用的代码
|
|
1199
|
+
- gosimple # 代码简化建议
|
|
1200
|
+
- ineffassign # 无效赋值
|
|
1201
|
+
- gocritic # 风格与性能建议
|
|
1202
|
+
- revive # golint 替代
|
|
1203
|
+
- misspell # 拼写检查
|
|
1204
|
+
- prealloc # 切片预分配建议
|
|
1205
|
+
- bodyclose # HTTP body 未关闭
|
|
1206
|
+
- noctx # HTTP 请求缺少 context
|
|
1207
|
+
- exhaustive # switch 穷举检查
|
|
1208
|
+
|
|
1209
|
+
linters-settings:
|
|
1210
|
+
govet:
|
|
1211
|
+
enable-all: true
|
|
1212
|
+
revive:
|
|
1213
|
+
rules:
|
|
1214
|
+
- name: unexported-return
|
|
1215
|
+
disabled: true
|
|
1216
|
+
```
|
|
1217
|
+
|
|
1218
|
+
```bash
|
|
1219
|
+
golangci-lint run ./...
|
|
1220
|
+
golangci-lint run --fix ./... # 自动修复部分问题
|
|
1221
|
+
```
|
|
1222
|
+
|
|
1223
|
+
### 12.3 go generate
|
|
1224
|
+
|
|
1225
|
+
```go
|
|
1226
|
+
//go:generate stringer -type=Status
|
|
1227
|
+
//go:generate mockgen -source=service.go -destination=mock_service.go
|
|
1228
|
+
//go:generate protoc --go_out=. --go-grpc_out=. proto/user.proto
|
|
1229
|
+
|
|
1230
|
+
type Status int
|
|
1231
|
+
|
|
1232
|
+
const (
|
|
1233
|
+
StatusPending Status = iota
|
|
1234
|
+
StatusActive
|
|
1235
|
+
StatusInactive
|
|
1236
|
+
)
|
|
1237
|
+
```
|
|
1238
|
+
|
|
1239
|
+
```bash
|
|
1240
|
+
go generate ./...
|
|
1241
|
+
```
|
|
1242
|
+
|
|
1243
|
+
---
|
|
1244
|
+
|
|
1245
|
+
## 13. 部署
|
|
1246
|
+
|
|
1247
|
+
### 13.1 交叉编译
|
|
1248
|
+
|
|
1249
|
+
```bash
|
|
1250
|
+
# Go 原生支持交叉编译
|
|
1251
|
+
GOOS=linux GOARCH=amd64 go build -o myapp-linux-amd64 ./cmd/myapp
|
|
1252
|
+
GOOS=darwin GOARCH=arm64 go build -o myapp-darwin-arm64 ./cmd/myapp
|
|
1253
|
+
GOOS=windows GOARCH=amd64 go build -o myapp.exe ./cmd/myapp
|
|
1254
|
+
|
|
1255
|
+
# 静态链接(无 CGO 依赖)
|
|
1256
|
+
CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o myapp ./cmd/myapp
|
|
1257
|
+
# -s 去掉符号表 -w 去掉 DWARF 调试信息 → 二进制缩小 ~25%
|
|
1258
|
+
|
|
1259
|
+
# 注入版本信息
|
|
1260
|
+
go build -ldflags="-X main.version=1.2.3 -X main.commit=$(git rev-parse --short HEAD)" ./cmd/myapp
|
|
1261
|
+
```
|
|
1262
|
+
|
|
1263
|
+
### 13.2 Docker 多阶段构建
|
|
1264
|
+
|
|
1265
|
+
```dockerfile
|
|
1266
|
+
# ---- 构建阶段 ----
|
|
1267
|
+
FROM golang:1.22-alpine AS builder
|
|
1268
|
+
|
|
1269
|
+
RUN apk add --no-cache git ca-certificates
|
|
1270
|
+
|
|
1271
|
+
WORKDIR /app
|
|
1272
|
+
COPY go.mod go.sum ./
|
|
1273
|
+
RUN go mod download
|
|
1274
|
+
|
|
1275
|
+
COPY . .
|
|
1276
|
+
RUN CGO_ENABLED=0 GOOS=linux go build \
|
|
1277
|
+
-ldflags="-s -w -X main.version=${VERSION}" \
|
|
1278
|
+
-o /app/server ./cmd/server
|
|
1279
|
+
|
|
1280
|
+
# ---- 运行阶段 ----
|
|
1281
|
+
FROM scratch
|
|
1282
|
+
# 或 FROM gcr.io/distroless/static-debian12(包含 CA 证书和时区数据)
|
|
1283
|
+
|
|
1284
|
+
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
|
1285
|
+
COPY --from=builder /app/server /server
|
|
1286
|
+
|
|
1287
|
+
EXPOSE 8080
|
|
1288
|
+
USER 65534:65534
|
|
1289
|
+
ENTRYPOINT ["/server"]
|
|
1290
|
+
```
|
|
1291
|
+
|
|
1292
|
+
```bash
|
|
1293
|
+
# 最终镜像通常 < 15 MB
|
|
1294
|
+
docker build -t myapp:latest .
|
|
1295
|
+
docker run -p 8080:8080 myapp:latest
|
|
1296
|
+
```
|
|
1297
|
+
|
|
1298
|
+
### 13.3 静态链接注意事项
|
|
1299
|
+
|
|
1300
|
+
```text
|
|
1301
|
+
CGO_ENABLED=0 生成完全静态链接的二进制,优点:
|
|
1302
|
+
- 可使用 scratch / distroless 最小镜像
|
|
1303
|
+
- 无系统库依赖,跨发行版部署
|
|
1304
|
+
- 安全扫描表面最小
|
|
1305
|
+
|
|
1306
|
+
注意:如果使用了需要 CGO 的库(如 go-sqlite3),需要用 musl-gcc 交叉编译
|
|
1307
|
+
或选择纯 Go 替代库(如 modernc.org/sqlite)
|
|
1308
|
+
```
|
|
1309
|
+
|
|
1310
|
+
---
|
|
1311
|
+
|
|
1312
|
+
## 14. 常见陷阱
|
|
1313
|
+
|
|
1314
|
+
### 14.1 Goroutine 泄漏
|
|
1315
|
+
|
|
1316
|
+
```go
|
|
1317
|
+
// BAD — channel 永远没人读,goroutine 永远阻塞
|
|
1318
|
+
func leaky() {
|
|
1319
|
+
ch := make(chan int)
|
|
1320
|
+
go func() {
|
|
1321
|
+
result := expensiveComputation()
|
|
1322
|
+
ch <- result // 永远阻塞,因为没有接收者
|
|
1323
|
+
}()
|
|
1324
|
+
// 函数返回,ch 无人接收
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
// GOOD — 用 context 或 buffered channel 防止泄漏
|
|
1328
|
+
func safe(ctx context.Context) (int, error) {
|
|
1329
|
+
ch := make(chan int, 1) // 缓冲区=1,即使没人读也不阻塞
|
|
1330
|
+
go func() {
|
|
1331
|
+
ch <- expensiveComputation()
|
|
1332
|
+
}()
|
|
1333
|
+
select {
|
|
1334
|
+
case result := <-ch:
|
|
1335
|
+
return result, nil
|
|
1336
|
+
case <-ctx.Done():
|
|
1337
|
+
return 0, ctx.Err()
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
// 检测泄漏:用 runtime.NumGoroutine() 或 goleak 库
|
|
1342
|
+
import "go.uber.org/goleak"
|
|
1343
|
+
func TestMain(m *testing.M) {
|
|
1344
|
+
goleak.VerifyTestMain(m)
|
|
1345
|
+
}
|
|
1346
|
+
```
|
|
1347
|
+
|
|
1348
|
+
### 14.2 Map 并发读写
|
|
1349
|
+
|
|
1350
|
+
```go
|
|
1351
|
+
// BAD — map 并发读写会 panic: concurrent map writes
|
|
1352
|
+
// Go 运行时在检测到并发 map 操作时会直接 fatal(不是 panic,无法 recover)
|
|
1353
|
+
|
|
1354
|
+
// GOOD 方案一:sync.Mutex
|
|
1355
|
+
type SafeMap struct {
|
|
1356
|
+
mu sync.RWMutex
|
|
1357
|
+
m map[string]int
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
func (s *SafeMap) Get(key string) (int, bool) {
|
|
1361
|
+
s.mu.RLock()
|
|
1362
|
+
defer s.mu.RUnlock()
|
|
1363
|
+
v, ok := s.m[key]
|
|
1364
|
+
return v, ok
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
func (s *SafeMap) Set(key string, val int) {
|
|
1368
|
+
s.mu.Lock()
|
|
1369
|
+
defer s.mu.Unlock()
|
|
1370
|
+
s.m[key] = val
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
// GOOD 方案二:sync.Map(适合读多写少或 key 稳定的场景)
|
|
1374
|
+
var cache sync.Map
|
|
1375
|
+
cache.Store("key", "value")
|
|
1376
|
+
if v, ok := cache.Load("key"); ok {
|
|
1377
|
+
fmt.Println(v)
|
|
1378
|
+
}
|
|
1379
|
+
```
|
|
1380
|
+
|
|
1381
|
+
### 14.3 defer 陷阱
|
|
1382
|
+
|
|
1383
|
+
```go
|
|
1384
|
+
// 陷阱一:循环中的 defer
|
|
1385
|
+
// BAD — defer 在函数退出时才执行,循环中会积累大量 defer
|
|
1386
|
+
func processFiles(paths []string) error {
|
|
1387
|
+
for _, path := range paths {
|
|
1388
|
+
f, err := os.Open(path)
|
|
1389
|
+
if err != nil { return err }
|
|
1390
|
+
defer f.Close() // 所有文件直到函数返回才关闭!
|
|
1391
|
+
}
|
|
1392
|
+
return nil
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
// GOOD — 封装到子函数
|
|
1396
|
+
func processFiles(paths []string) error {
|
|
1397
|
+
for _, path := range paths {
|
|
1398
|
+
if err := processOneFile(path); err != nil {
|
|
1399
|
+
return err
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
return nil
|
|
1403
|
+
}
|
|
1404
|
+
func processOneFile(path string) error {
|
|
1405
|
+
f, err := os.Open(path)
|
|
1406
|
+
if err != nil { return err }
|
|
1407
|
+
defer f.Close()
|
|
1408
|
+
// ...
|
|
1409
|
+
return nil
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
// 陷阱二:defer 参数求值时机
|
|
1413
|
+
x := 1
|
|
1414
|
+
defer fmt.Println(x) // 打印 1,不是 2
|
|
1415
|
+
x = 2
|
|
1416
|
+
// 解法:用闭包
|
|
1417
|
+
defer func() { fmt.Println(x) }() // 打印 2
|
|
1418
|
+
```
|
|
1419
|
+
|
|
1420
|
+
### 14.4 nil 接口 vs nil 指针
|
|
1421
|
+
|
|
1422
|
+
```go
|
|
1423
|
+
// Go 接口内部有两个字段:(type, value)
|
|
1424
|
+
// 只有 type 和 value 都为 nil 时,接口才 == nil
|
|
1425
|
+
|
|
1426
|
+
type MyError struct{ Msg string }
|
|
1427
|
+
func (e *MyError) Error() string { return e.Msg }
|
|
1428
|
+
|
|
1429
|
+
func getError() error {
|
|
1430
|
+
var p *MyError = nil
|
|
1431
|
+
return p // 返回的 error 接口:(type=*MyError, value=nil),不等于 nil!
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
err := getError()
|
|
1435
|
+
fmt.Println(err == nil) // false!
|
|
1436
|
+
|
|
1437
|
+
// GOOD — 直接返回 nil
|
|
1438
|
+
func getError() error {
|
|
1439
|
+
var p *MyError = nil
|
|
1440
|
+
if p == nil {
|
|
1441
|
+
return nil // 返回 (type=nil, value=nil)
|
|
1442
|
+
}
|
|
1443
|
+
return p
|
|
1444
|
+
}
|
|
1445
|
+
```
|
|
1446
|
+
|
|
1447
|
+
### 14.5 闭包变量捕获
|
|
1448
|
+
|
|
1449
|
+
```go
|
|
1450
|
+
// BAD (Go < 1.22) — 循环变量被闭包共享
|
|
1451
|
+
for _, item := range items {
|
|
1452
|
+
go func() {
|
|
1453
|
+
process(item) // 所有 goroutine 可能都用最后一个 item
|
|
1454
|
+
}()
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
// GOOD (Go < 1.22) — 显式传参
|
|
1458
|
+
for _, item := range items {
|
|
1459
|
+
item := item // 重新绑定到新变量
|
|
1460
|
+
go func() {
|
|
1461
|
+
process(item)
|
|
1462
|
+
}()
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
// Go 1.22+ — 循环变量每次迭代都是新变量,此问题已修复
|
|
1466
|
+
// 但在 go.mod 中 go 版本 < 1.22 时仍需注意
|
|
1467
|
+
```
|
|
1468
|
+
|
|
1469
|
+
### 14.6 切片陷阱
|
|
1470
|
+
|
|
1471
|
+
```go
|
|
1472
|
+
// 子切片与原切片共享底层数组
|
|
1473
|
+
original := []int{1, 2, 3, 4, 5}
|
|
1474
|
+
sub := original[1:3] // [2, 3]
|
|
1475
|
+
sub[0] = 99
|
|
1476
|
+
fmt.Println(original) // [1, 99, 3, 4, 5] — 被修改了!
|
|
1477
|
+
|
|
1478
|
+
// GOOD — 完整复制
|
|
1479
|
+
sub := make([]int, 2)
|
|
1480
|
+
copy(sub, original[1:3])
|
|
1481
|
+
|
|
1482
|
+
// 或使用三索引切片限制容量
|
|
1483
|
+
sub := original[1:3:3] // len=2, cap=2,append 不会影响原数组
|
|
1484
|
+
```
|
|
1485
|
+
|
|
1486
|
+
---
|
|
1487
|
+
|
|
1488
|
+
## 15. 项目结构推荐
|
|
1489
|
+
|
|
1490
|
+
```text
|
|
1491
|
+
myservice/
|
|
1492
|
+
├── cmd/
|
|
1493
|
+
│ └── server/
|
|
1494
|
+
│ └── main.go # 入口,仅做依赖注入和启动
|
|
1495
|
+
├── internal/ # 私有代码,外部不可 import
|
|
1496
|
+
│ ├── handler/ # HTTP/gRPC handler
|
|
1497
|
+
│ ├── service/ # 业务逻辑
|
|
1498
|
+
│ ├── repository/ # 数据访问
|
|
1499
|
+
│ ├── model/ # 领域模型
|
|
1500
|
+
│ └── middleware/ # 中间件
|
|
1501
|
+
├── pkg/ # 公共库,可被外部 import
|
|
1502
|
+
│ ├── httputil/
|
|
1503
|
+
│ └── logger/
|
|
1504
|
+
├── api/ # API 定义(OpenAPI / Proto)
|
|
1505
|
+
│ └── proto/
|
|
1506
|
+
├── migrations/ # 数据库迁移
|
|
1507
|
+
├── configs/ # 配置文件模板
|
|
1508
|
+
├── scripts/ # 构建/部署脚本
|
|
1509
|
+
├── Dockerfile
|
|
1510
|
+
├── Makefile
|
|
1511
|
+
├── go.mod
|
|
1512
|
+
├── go.sum
|
|
1513
|
+
└── .golangci.yml
|
|
1514
|
+
```
|
|
1515
|
+
|
|
1516
|
+
---
|
|
1517
|
+
|
|
1518
|
+
## Agent Checklist
|
|
1519
|
+
|
|
1520
|
+
以下检查项供 AI Agent 在代码审查和生成时参考:
|
|
1521
|
+
|
|
1522
|
+
### 必查项 (MUST)
|
|
1523
|
+
|
|
1524
|
+
- [ ] 所有 error 都已处理,没有 `_ = err` 或忽略返回值
|
|
1525
|
+
- [ ] 所有 HTTP 请求使用了带超时的 `context.Context`
|
|
1526
|
+
- [ ] `http.Client` 和 `http.Server` 都设置了 `Timeout`
|
|
1527
|
+
- [ ] 所有 goroutine 有明确的退出机制(context / channel / WaitGroup)
|
|
1528
|
+
- [ ] map 在并发场景使用了 `sync.Mutex` 或 `sync.Map`
|
|
1529
|
+
- [ ] `defer f.Close()` 在循环中没有使用(应封装到子函数)
|
|
1530
|
+
- [ ] 返回 error 接口时没有返回类型化的 nil 指针
|
|
1531
|
+
- [ ] `database/sql` 连接池参数已配置(MaxOpen / MaxIdle / ConnMaxLifetime)
|
|
1532
|
+
- [ ] `resp.Body.Close()` 在所有 HTTP 响应路径中都有调用(包括错误路径)
|
|
1533
|
+
- [ ] Dockerfile 使用多阶段构建,最终镜像基于 scratch 或 distroless
|
|
1534
|
+
|
|
1535
|
+
### 应查项 (SHOULD)
|
|
1536
|
+
|
|
1537
|
+
- [ ] 使用 `errors.Is` / `errors.As` 而非 `==` 比较或类型断言
|
|
1538
|
+
- [ ] 错误信息包含上下文(哪个函数、哪个参数)
|
|
1539
|
+
- [ ] 使用 `strings.Builder` 而非 `+` 拼接多个字符串
|
|
1540
|
+
- [ ] 切片预分配了容量 `make([]T, 0, expectedLen)`
|
|
1541
|
+
- [ ] 接口方法数 <= 3,超过则拆分
|
|
1542
|
+
- [ ] 使用 `t.Parallel()` 加速测试
|
|
1543
|
+
- [ ] table-driven test 覆盖边界情况
|
|
1544
|
+
- [ ] `golangci-lint` 配置中启用了 errcheck / govet / staticcheck / bodyclose / noctx
|
|
1545
|
+
- [ ] gRPC 服务使用了 recovery / logging interceptor
|
|
1546
|
+
- [ ] 日志使用结构化 logger(zap / slog)而非 `log.Printf`
|
|
1547
|
+
|
|
1548
|
+
### 可查项 (MAY)
|
|
1549
|
+
|
|
1550
|
+
- [ ] 热路径使用 `sync.Pool` 复用 buffer
|
|
1551
|
+
- [ ] 使用 `go build -ldflags="-s -w"` 减小二进制体积
|
|
1552
|
+
- [ ] Benchmark 覆盖核心算法,使用 `benchstat` 对比
|
|
1553
|
+
- [ ] 使用 `goleak.VerifyTestMain` 检测 goroutine 泄漏
|
|
1554
|
+
- [ ] 使用三索引切片 `s[low:high:max]` 防止子切片污染原数组
|
|
1555
|
+
- [ ] Context.Value 仅用于请求范围元数据,不用于传递业务参数
|
|
1556
|
+
|
|
1557
|
+
---
|
|
1558
|
+
|
|
1559
|
+
**知识ID**: `golang-complete`
|
|
1560
|
+
**领域**: development
|
|
1561
|
+
**类型**: standards
|
|
1562
|
+
**难度**: intermediate-advanced
|
|
1563
|
+
**质量分**: 97
|
|
1564
|
+
**维护者**: dev-team@umadev.com
|
|
1565
|
+
**最后更新**: 2026-03-28
|