关于包管理:插件化工程R文件瘦身技术方案-京东云技术团队

随着业务的倒退及版本迭代,客户端工程中一直减少新的业务逻辑、引入新的资源,随之而来的问题就是安装包体积变大,后期各个业务模块通过无用资源删减、大图压缩或转上云、AB试验业务逻辑下线或其余伎俩在升高包体积上获得了肯定的成绩。 在瘦身的过程中咱们关注到了R文件瘦身的概念,目前京东APP是反对插件化的,有业务插件工程、宿主工程,对业务插件包文件进行剖析,发现除了惯例的资源及代码外,R类文件大略占包体积的3%~5%左右,对宿主工程包文件进行剖析,R类文件占比也有3%左右。咱们先后在对R类文件瘦身的可行性及业界开源我的项目进行调研后,摸索出了一套实用于插件化工程的R文件瘦身技术计划。 实践根底—R文件R文件也就是咱们日常工作中常常打交道的R.java文件,在Android开发标准中咱们须要将利用中用到的资源别离放入专门命名的资源目录中,内部化利用资源以便对其进行独自保护。 内部化利用资源后,咱们可在我的项目中应用R类ID来拜访这些资源,且R类ID具备唯一性。 public class MainActivity extends BaseActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); }}在android apk打包流程中R类文件是由aapt(Android Asset Packaing Tool)工具打包生成的,在生成R类文件的同时对资源文件进行编译,生成resource.arsc文件,resource.arsc文件相当于一个文件索引表,应用层代码通过R类ID 能够拜访到对应的资源。 R文件瘦身的可行性剖析日常开发阶段,在主工程中通过R.xx.xx的形式援用资源,通过编译后R类援用对应的常量会被编译进class中。 setContentView(2131427356);这种变动叫做内联,内联是java的一种机制(如果一个常量被标记为static final,在java编译的过程中会将常量内联到代码中,缩小一次变量的内存寻址)。 非主工程中,R类资源ID以援用的形式编译进class中,不会产生内联。 setContentView(R.layout.activity_main);产生这种景象的起因是AGP打包工具导致的。具体细节,大家能够去查阅一下android gradle plugin在R文件上的处理过程。 论断:R类id内联后程序可运行,但并非所有的工程都会主动产生内联景象,咱们须要通过技术手段在适合的机会将R类id内联到程序中,内联实现后,因为不再依赖R类文件,则能够将R类文件删除,在利用失常运行的同时,达到包瘦身目标。 插件化工程R文件瘦身实战制订技术计划目前京东Android客户端是反对插件化的,整个插件化工程蕴含公共库(是一个aar工程,用来寄存组件和宿主共用的类和资源)、业务插件(插件工程是一个独立的工程,编译产物能够运行在宿主环境中)、宿主(主工程,提供运行环境)。在插件化的过程中为了避免宿主和插件资源抵触,通过批改插件packageId保障了资源的唯一性。因为公共资源库、宿主是被很多业务依赖,对这两个我的项目进行改变评估影响波及比拟多,插件个别都是业务模块自行保护,不存在被依赖问题,所以先在业务插件模块进行R类瘦身实际。 对业务插件工程打出的包进行反编译当前,发现R类ID无内联景象,且R类文件具备肯定的大小,对包内的R文件进行剖析,发现R文件中仅蕴含业务本身的资源,不蕴含业务依赖的公共资源R类。 public View onCreateView(LayoutInflater paramLayoutInflater, ViewGroup paramViewGroup, Bundle paramBundle) { this.b = paramLayoutInflater.inflate(R.layout.lib_pd_main_page, paramViewGroup, false); this.h = (PDBuyStatusView)this.b.findViewById(R.id.pd_buy_status_view); this.f = (PageRecyclerView)this.b.findViewById(R.id.lib_pd_recycle_view);} 联合对业界开源我的项目的调研剖析,尝试制订合乎京东商城的技术计划并优先在业务插件内实现R类ID内联并删除对应的R文件。 1.通过transformapi 收集要解决的class文件Transform 是 Android Gradle 提供的操作字节码的一种形式,它在 class 编译成 dex 之前通过一系列 Transform 解决来实现批改.class文件。 ...

June 13, 2023 · 2 min · jiezi

关于包管理:打造手淘极简包的轻量化框架

作者:周松(北傲) 现在app冗余与包大小始终都是很多业务挥之不去的优化项。行业内很多极简包如雨后春笋般冒出来。又或者是很多业务对极简包的摸索也有踊跃的尝试。 极简包带来的价值,不仅是包大小上的量变,更是用户下载转化率和投放带来的正向效应,线下下沉市场的开拓具备重要价值,对拉新转化率影响很大。 个别极简包会有两种计划: 1、作为一个套壳App,套了一层H5。次要链路由前端去买通交易流程,而后通过更新计划疏导用户降级; 2、作为一个套壳App,套了一层H5。次要链路由前端去买通交易流程,而后通过插件化的模式去动静更新Native版本的app。 无论采纳上述哪种形式,作为H5的载体,只应用原生的web去关上页面体验感仍不是很好。同时还会伴有各种H5的适配联调和优化。而对于H5比拟宏大的业务,如手淘,很多页面前端去适配有极大的工作量,投入产出比不高。 故手淘极简包提供第三种计划: 3、主页由多个TAB实现,能够Native或者H5,由业务本人去抉择,详情页通过H5去加载。前期降级链路是传统Apk更新或者插件化由业务方本人去抉择。 由此手淘极简包我的项目拆散了一个能够疾速搭建极简App的框架。可供作为根底脚手架,疾速搭建出本人业务的极简版App。 MTASMini TaoBao Application Scaffold MTAS是手淘极简版利用脚手架,是基于疾速搭建极简包我的项目的App框架。 现在手机淘宝极简版采纳此极简包根底框架,包大小4M+。 基础架构思维导图 极简根底框架从构造上次要分为几个局部: 极简根底服务 极简根底库 -- 次要集成团体的根底依赖,比方:网络、容器、登录等。都是通过裁剪或重构过的精简版,相较于原版冗余简单性能多,精简版的根底依赖轻量简略性能少。只有须要的根底性能,不去额定减少包大小的累赘。 对立api层 -- 要想疾速搭建一个轻量的app,根底的性能封装不能少,在这个模块中,对立实现罕用的性能,若是业务接入,不须要反复造轮子。只须要简略调用即可。 极简外围容器 极简外围容器由mini-网页容器sdk作为载体,外围实现极简版的相干对立拦挡导航。反对登录、back、跳转、外链拉起、降级等性能。启用多webview计划代替原生webview的缓存后退后退等策略,使页面过渡更加晦涩。进入前后级更加疾速,交互更好。内置缓存冷启及首次启动达到秒开级别,晋升用户体验。 极简降级链路 能够同时反对插件化下载、装置、切换。也能够反对传统的利用apk下载、装置、降级。通过流式调用管制下载相干的操作,调用方能够自定义下载流来做本人想做的事件,例如一些流前查看,流后处理,开关管制等等。 极简业务组件 搭建一个简版首页的根底视图组件、罕用的下拉刷新、上拉加载组件、裁剪过的recyclerView等等组件,能够反对搭建简略的首页。 具体设计极简包根底框架自下而上,从根底依赖到下层业务,一层层做解耦和拆散。 业务能够调用根底性能,也能够自行扩大性能。比拟灵便。 极简包定义一套轻量化计划,外围解决以下三类问题: 包大小:通过轻量根底服务,以及Native + H5业务状态缩减包体大小至4M+;降级转化:插件化底座实现静默更新,插件静默更新 + 兜底APK更新 + 利用市场自动更新,整体晋升降级率;端内体验: Native化外围页面、H5预渲染、H5详情极速版晋升外围链路加载体验登录,保障包体大小前提下,反对支付宝登录、手机号一键登录&验证码登录、首页强疏导。极简版架构设计 极简根底服务极简根底库次要集成团体的根底依赖。都是通过裁剪或重构过的精简版,相较于原版冗余简单性能多,精简版的根底依赖轻量简略性能少。只有须要的根底性能,不去额定减少包大小的累赘。 以下介绍几个次要的裁剪根底库: 网页容器sdk裁剪比照图 mini-网页容器sdk,是一个可扩大的 Hybrid 利用解决方案,为客户端内的 Web 页面提供了弱小、易用的 WebView 容器。轻量且易用,目前只有500kb,不依赖UC内核,做到小而简。 图片库sdk裁剪比照图 mini-图片库sdk,精简无线图片库sdk是阿里巴巴Android端集图像加载、显示、解决、监控于一体的一站式解决方案。笼罩业内支流图片库外围个性,同时就地取材联合团体CDN图片解决规定,旨在更无效地节俭流量、更优越的内存占用、更极致的性能优化、更晦涩的加载体验。简化线程调度框架,缩小图片格式反对,轻量图片降级计划,保留根底性能,对模块合并,代码优化,膨胀一些负责性能。 网关sdk裁剪比照图 mini-网关sdk ,精简API网关平台,为客户端、H5和服务端提供对立、快捷、牢靠的API接入以及监控报表服务。保留平安框架的能力,保障挪动平台利用完整性、利用执行环境可信性、数据机密性。原生网络库减小包大小。提供plugin供前端调用。 mini-数据采集sdk,一套面向客户端开发的目前团体内笼罩app最多的数据采集SDK,具备数据安全级别高、数据达到率高、传输流量小等特点。优化代码做裁剪,去网络底层sdk依赖。 mini-登录sdk,对立登录SDK为淘系APP打造统一的账户体验,并且与平安深度集成,提供统一的平安水位。 代码裁剪,突出一键登录及sso登录,进步登录效率。缩减链路长的登录。 极简包依赖大小比照图 极简包根底依赖裁剪过后,正向收益是非常显著的,无效的升高了包大小,去除不必要的依赖和性能。使利用达到轻量化和简洁化。负向影响也能够意料,性能多样性升高,可供的抉择缩小。 对立api层极简包根底框架中做了一套对立根底实现。集成罕用的工具类,对性能的应用也做了封装。 根底实现包类展现 每个包的划分使职责明确。应用方能够间接用外面的各种办法。也能够本人自定义须要的性能,或者实现接口扩大想要的能力。 极简外围容器容器外围承接了业务的根底性能,保障失常的H5流程及平安相干的反对。同时也能够自定义实现业务方本人的扩大。 拦挡导航 路由拦挡导航次要分为两个局部:替换器(Replace)和拦截器(Filter)。拦截器次要负责拦挡并且做一些安全性的校验以及解决;替换器次要解决业务上通用的性能,不便调试测试的性能等等。 ...

January 17, 2022 · 1 min · jiezi

关于包管理:包管理NPM

NPMnvmnpm1. NVMNVM(Node Version Manager):Node版本治理 Windows上装置地址 下载压缩包间接装置即可常用命令 查看 //查看可装置的node版本nvm ls available//查看曾经装置的node版本nvm ls装置与卸载 //装置一个nodenvm install [version]//卸载一个nodenvm uninstall [version]切换 //切换node版本nvm use [version]2 NPMNPM(Node Package Manager):Node包治理 包治理上传包脚本NRMNPX2.1 包治理全局装置 //全局装置与卸载 不指定version默认为以后最新版本npm install(i) package[@verison] --global(-g)npm uninstall package[@verison] -global(-g)查看 //查看包可装置的版本npm view package[@verison] versions//查看装置的所有包npm list(ls)//查看已装置的一个包npm list(ls) | grep package本地装置 //初始化package.jsonnpm init -y//装置至生产环境npm i package[@verison] [--save]//装置至开发环境npm i package[@verison] --dev(-D)//卸载不必增加额定的修饰符更新版本package.json中的版本锁定 :不锁定版本 - 更新三位^X.X.X:锁定第一位 - 更新后两位~X.X.X:锁定前两位 - 更新最初一位X.X.X :锁定三位 - 指定版本更新 //依据锁定查看可更新信息npm outdated//更新至锁定的最新版本npm update//装置指定版本npm i package@version革除缓存 npm cache clean --force包第一次装置失败后再次装置也可能失败,须要革除缓存2.2 上传包创立一个包 ...

October 28, 2021 · 1 min · jiezi

go-包管理-踩坑

安装或者 运行 go build 时候报错: go: finding github.com/modern-go/concurrent latestgo: finding gopkg.in/check.v1 latestgo: golang.org/x/net@v0.0.0-20190503192946-f4e77d36d62c: unrecognized import path "golang.org/x/net" (https fetch: Get https://golang.org/x/net?go-get=1: dial tcp 216.239.37.1:443: connectex: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.)说明你需要proxy了(其实用了proxy有时候也没用),或者是用 module 的 replace 来转一下,这个方法有以下缺点:1.有些包还是转发失败2.需要一个个的设置很麻烦 找了许久,另外一种办法设置global go proxy 具体方法如下:1.先清除 cache ,到特定目录删除文件2.window下 打开 power shell 然后执行如下命令: ...

June 25, 2019 · 1 min · jiezi

Go 包依赖管理工具 —— govendor

govendor 是一个基于 vendor 机制实现的 Go 包依赖管理命令行工具。与原生 vendor 无侵入性融合,也支持从其他依赖管理工具迁移,可以很方便的实现同一个包在不同项目中不同版本、以及无相互侵入的开发和管理。vendor 特性最开始的时候,Go 并没有提供较为妥当的包管理工具。从 1.5 版本开始提供了 vendor 特性,但需要手动设置环境变量 GO15VENDOREXPERIMENT=1。在执行 go build 或 go run 命令时,会按照以下顺序去查找包:当前包下的 vendor 目录向上级目录查找,直到找到 src 下的 vendor 目录在 GOROOT 目录下查找在 GOPATH 下面查找依赖包在发布 1.6 版本时,该环境变量的值已经默认设置为 1 了,该值可以使用 go env 命令查看。在发布 1.7 版本时,已去掉该环境变量,默认开启 vendor 特性。vendor 使用建议一个库工程(不包含 main 的 package)不应该在自己的版本控制中存储外部的包在 vendor 目录中,除非有特殊原因并且知道为什么要这么做。在一个应用中,(包含 main 的 package),建议只有一个 vendor 目录,且在代码库一级目录。govendor 简介govendor 是一个基于 vendor 目录机制的包管理工具。支持从项目源码中分析出依赖的包,并从 $GOPATH 复制到项目的 vendor 目录下支持包的指定版本,并用 vendor/vendor.json 进行包和版本管理,这点与 PHP 的 Composer 类似支持用 govendor add/update 命令从 $GOPATH 中复制依赖包如果忽略了 vendor// 文件,可用 govendor sync 恢复依赖包可直接用 govendor fetch 添加或更新依赖包可用 govendor migrate 从其他 vendor 包管理工具中一键迁移到 govendor支持 Linux,macOS,Windows,甚至现有所有操作系统支持 Git、Hg、SVN,BZR(必须指定一个路径)govendor 使用要求:项目必须在 $GOPATH/src 目录下如果 Go 版本为 1.5,则必须手动设置环境变量 set GO15VENDOREXPERIMENT=1安装go get -u github.com/kardianos/govendor为了方便快捷使用 govendor,建议将 $GOPATH/bin 添加到 PATH 中。Linux/macOS 如下设置:export PATH="$GOPATH/bin:$PATH"初始化在项目根目录下执行以下命令进行 vendor 初始化:govendor init项目根目录下即会自动生成 vendor 目录和 vendor.json 文件。此时 vendor.json 文件内容为:{ “comment”: “”, “ignore”: “test”, “package”: [], “rootPath”: “govendor-example”}常用命令将已被引用且在 $GOPATH 下的所有包复制到 vendor 目录govendor add +external仅从 $GOPATH 中复制指定包govendor add gopkg.in/yaml.v2列出代码中所有被引用到的包及其状态govendor list e github.com/gin-contrib/sse e github.com/gin-gonic/gin e github.com/gin-gonic/gin/binding e github.com/gin-gonic/gin/internal/json e github.com/gin-gonic/gin/render e github.com/golang/protobuf/proto e github.com/mattn/go-isatty e github.com/ugorji/go/codec e gopkg.in/go-playground/validator.v8 e gopkg.in/yaml.v2pl govendor-example m github.com/json-iterator/go m golang.org/x/sys/unix列出一个包被哪些包引用govendor list -v fmt s fmt ├── e github.com/gin-contrib/sse ├── e github.com/gin-gonic/gin ├── e github.com/gin-gonic/gin/render ├── e github.com/golang/protobuf/proto ├── e github.com/ugorji/go/codec ├── e gopkg.in/go-playground/validator.v8 ├── e gopkg.in/yaml.v2 └── pl govendor-example从远程仓库添加或更新某个包(不会在 $GOPATH 也存一份)govendor fetch golang.org/x/net/context安装指定版本的包govendor fetch golang.org/x/net/context@a4bbce9fcae005b22ae5443f6af064d80a6f5a55govendor fetch golang.org/x/net/context@v1 # Get latest v1..* tag or branch.govendor fetch golang.org/x/net/context@=v1 # Get the tag or branch named “v1”.只格式化项目自身代码(vendor 目录下的不变动)govendor fmt +local只构建编译项目内部的包govendor install +local只测试项目内部的测试案例govendor test +local构建所有 vendor 包govendor install +vendor,^program拉取所有依赖的包到 vendor 目录(包括 $GOPATH 存在或不存在的包)govendor fetch +out包已在 vendor 目录,但想从 $GOPATH 更新govendor update +vendor已修改了 $GOPATH 里的某个包,现在想将已修改且未提交的包更新到 vendorgovendor update -uncommitted <updated-package-import-path>Fork 了某个包,但尚未合并,该如何引用到最新的代码包govendor fetch github.com/normal/pkg::github.com/myfork/pkg此时将从 myfork 拉取代码,而不是 normal。vendor.json 中记录了依赖包信息,该如何拉取更新govendor syncgovendor 子命令各子命令详细用法可通过 govendor COMMAND -h 或阅读 github.com/kardianos/govendor/context 查看源码包如何实现的。子命令功能init创建 vendor 目录和 vendor.json 文件list列出&过滤依赖包及其状态add从 $GOPATH 复制包到项目 vendor 目录update从 $GOPATH 更新依赖包到项目 vendor 目录remove从 vendor 目录移除依赖的包status列出所有缺失、过期和修改过的包fetch从远程仓库添加或更新包到项目 vendor 目录(不会存储到 $GOPATH)sync根据 vendor.json 拉取相匹配的包到 vendor 目录migrate从其他基于 vendor 实现的包管理工具中一键迁移get与 go get 类似,将包下载到 $GOPATH,再将依赖包复制到 vendor 目录license列出所有依赖包的 LICENSEshell可一次性运行多个 govendor 命令govendor 状态参数状态缩写含义+locall本地包,即项目内部编写的包+externale外部包,即在 GOPATH 中、却不在项目 vendor 目录+vendorv已在 vendor 目录下的包+stds标准库里的包+excludedx明确被排除的外部包+unusedu未使用的包,即在 vendor 目录下,但项目中并未引用到+missingm被引用了但却找不到的包+programp主程序包,即可被编译为执行文件的包+outside 相当于状态为 +external +missing+all 所有包支持状态参数的子命令有:list、add、update、remove、fetchGo modules普大喜奔的是,从 Go 1.11 版本开始,官方已内置了更为强大的 Go modules 来一统多年来 Go 包依赖管理混乱的局面(Go 官方之前推出的 dep 工具也几乎胎死腹中),并且将在 1.12 版本中正式默认开启。目前已受到社区的看好和强烈推荐,建议新项目采用 Go modules。参考govendor 项目golang使用vendor目录来管理依赖包Golang包管理工具之govendor的使用感谢您的阅读,觉得内容不错,点个赞吧 ????原文地址: https://shockerli.net/post/go… ...

March 25, 2019 · 2 min · jiezi

使用 govendor 管理你的 go 项目包版本

govendor 是 go 的一个比较好用包版本管理工具。主要用来保证 go 项目在协同开发或发版部署时,保证部署安装的依赖包版本对当前项目是稳定可用的。为什么要使用包版本管理工具java 的 maven,php 的 composer,nodejs 的 npm,python 的 requirement.txt,golang 的 govendor。例1:你的项目依赖一个github.com/foo 1.0.0的包,如果不使用包版本管理工具,他人在本地部署安装你的项目时,安装的包版本可能是最新的github.com/foo 2.0.0,如果两个版本存在兼容问题,就会出现crashed。例2:使用 go get 安装的项目依赖包的存放位置为 $GOPATH/src,即与你的项目路径同级,我们使用 git 时就没办法管理这些依赖包,不能也不应该将它们也提交到git仓库,如果提供一个包版本说明说,将说明书提交仓库,他人则根据此说明书安装依赖包。为解决此问题,govendor出现了,govendor会将项目依赖的包版本记录到your_proj/vendor/vendor.json中,后期将此文件提交至 git 仓库,则其他人 pull or clone 你的项目到本地后,即可使用 govendor 安装稳定的包依赖。govendor 工作流首先要部署好你的 go 环境,并将 $GOPATH/bin 路径加载到系统PATH中。我们将体验一遍如何使用govendor管理你的项目包版本,及如何安装他人的govendor管理的go项目(这点才是精华,很多博文都不提及,为什么版本管理,不就是为了能让程序在其他地方也能稳定运行嘛)。安装govendorgo get -u -v github.com/kardianos/govendor#运行 govendor 检测安装结果govendor如果能看到帮助提示信息,说明安装ok。项目初始化使用 govendor 初始化你的项目,将会在工程目录下自动创建 vendor 目录及 vendor/vendor.json 文件。如果是已有项目,也没关系,govendor允许你在项目开发的任何阶段去使用它,它总能将你的项目包版本管理起来。mkdir go_proj && cd go_proj# init projgovendor init#查看目录结构tree.└── vendor └── vendor.json1 directory, 1 file安装&管理包govendor get我们仍然可以通过 go get安装包到 $GOPATH/src下,但使用govendor get可以在安装包的同时将包纳入版本管理,而且会将包安装在$GOPATH/src/your_proj/vendor,更符合我们的要求。#安装在 $GOPATH/src 下go get github.com/go-sql-driver/mysql#安装在$GOPATH/src/your_proj/vendor下govendor get github.com/go-sql-driver/mysqlgovendor list & govendor addgovendor list可以帮助我们查看项目中引入的包的状态,即哪些是没有纳入版本管理的外部包,哪些是纳入版本管理的包,哪些是标准包,哪些是本地包等。govendor listStatus Types +local (l) packages in your project 你自己在项目中定义的包 +external (e) referenced packages in GOPATH but not in current project 使用 go get 安装的项目外部包 +vendor (v) packages in the vendor folder 使用 govendor get 安装的纳入版本管理的包 +std (s) packages in the standard library 标准包 fmt/time/runtime 等 +excluded (x) external packages explicitly excluded from vendoring 排除的外部包 +unused (u) packages in the vendor folder, but unused 安装但没引用的包 +missing (m) referenced packages but not found 引用但没安装的包 缺失了 +program (p) package is a main package 你的项目主包,它总会同 l 一起出现 pl 这个很好理解吧 +outside +external +missing +all +all packagesgovendor add则是方便我们在任何时间将项目包纳入版本管理。比如我们前期一直使用或现在偶然使用go get安装了一个项目的依赖包,此包是不会被记录在vendor/vendor.json中的,即没有纳入版本管理,那该如何将其纳入呢?go add +external执行上方命令即可,这样项目依赖的包都纳入了版本管理。提交git仓库在提交源码至git仓库时,我们没有必要将依赖包源文件也一并提交至仓库,所以 .gitignore 的编排要加上如下规则:# vi .gitignorevendor/*!vendor/vendor.json即排除vendor下的除vendor/vendor.json外的所有文件(这些文件其实就是依赖包),将vendor/vendor.json提交至git仓库即可。安装/部署 govendor 项目当我们从git仓库下载好govendor管理的golang项目时,需要安装好项目的包依赖,才可以正常的运行程序,类似 composer install的作用,这里则是使用govendor sync。这里使用我的一个 govendor 管理的基于Gin的MVC简易框架给大家演示一下:cd $GOPATH/src && git clone git@github.com:sqrtcat/easy-gin.git && cd easy-gingovendor sync运行程序即可,简单! ...

March 16, 2019 · 1 min · jiezi

golang 之 import 和 package 的使用

golang 使用包 package 来管理定义模块,可以使用 import 关键字来导入使用。如果导入的是 go 自带的包,则会去安装目录 $GOROOT/src 按包路径加载,如 fmt 包如果是我们 go get 安装或自定义的包,则会去 $GOPATH/src 下加载package 的定义go import 的包是由 包路径/包名 组合而成的,例如导入我们自定义的 baz 包,包路径为 $GOPATH/src/foo/bar/baz,baz 包的源码都存放在此目录下。我们需要规范的将 baz 包中源码的 package 定义为 baz,就定义好一个可 import 载入的的包了。hello 模块//$GOPATH/src/foo/bar/baz/hello.gopackage bazimport ( “fmt”)// 模块初始化函数 import 包时被调用func init() { fmt.Println(“hello module init function”)}func Hello() { return “hello”}world 模块//$GOPATH/src/foo/bar/baz/world.gopackage bazimport ( “fmt”)// 模块初始化函数 import 包时被调用func init() { fmt.Println(“world module init function”)}func World() string { return “world”}package mainimport ( “fmt” “foo/bar/baz” //引入我们自定义的包)func main() { fmt.Println(baz.Hello(), baz.World())}import的使用普通操作import ( “fmt” “log” “foo/bar/baz”)普通导入就是按照加载机制,将要使用的包导入进来,然后使用 packageName.MethodName 的方式调用包内的方法即可。注意如果要包方法在其他包中可以调用,包方法需要首字母大写,例如:fmt.Println() fmt.Printf()。别名操作package mainimport ( “fmt” myBaz “foo/bar/baz”)func main() { fmt.Println(myBaz.Hello(), myBaz.World())}如果两个包的包名存在冲突,或者包名太长需要简写时,我们可以使用别名导入来解决。点操作package mainimport ( “fmt” . “foo/bar/baz”)func main() { fmt.Println(Hello(), World()) // 直接使用包内的方法即可 不需要显式使用包名}. 导入可以让包内的方法注册到当前包的上下文中,直接调用方法名即可,不需要再加包前缀。下划线操作package mainimport ( “fmt” _ “foo/bar/baz”)func main() { fmt.Println(baz.Hello(), baz.World()) // 错误 _ 并没有导入包 只是引入并执行包模块的 init 方法}_ 是包引用操作,只会执行包下各模块中的 init 方法,并不会真正的导入包,所以不可以调用包内的其他方法。相信对很多 phper 来说遵循 PSR4 的 Namespace 会将与路径紧密相关命名空间也作为类名的一部分,而 golang 则只将模块目录文件夹名作为包名,前面的路径只是用来导入而和包名无关,还是有一点点需要注意的。 ...

February 21, 2019 · 1 min · jiezi