精华内容
下载资源
问答
  • Golang 项目之配置文件

    2021-05-15 18:42:09
    golang 对于初学者还算友好, 写代码很好入门, 但业界对于golang工程与项目的BP却比较缺少,或者是有很多方为此争论不休,就比依赖管理工具就搞出了许多个,如 知名的有dep, vgo和golang 官方的 go module, 也可能...

    相信对于很多gopher 而言, 我这篇文章,算比较初级,我是一个一年多经验的golang程序员,有着5年左右的编程经验。

    golang 对于初学者还算友好, 写代码很好入门, 但业界对于golang工程与项目的BP却比较缺少,或者是有很多方为此争论不休,就比依赖管理工具就搞出了许多个,如 知名的有dep, vgo和golang 官方的 go module, 也可能是我所知有限的缘故, 希望大家不吝赐教。

    既然要说go项目的配置文件,那对于配置文件先做一个简单的介绍:

    配置文件的格式

    yaml

    yaml是最近很流行的一种描述语言,上手比较简单学习成本低,结构清晰, 5分钟即可掌握所有细节

    阮一峰老师的yaml语法教程

    一个简单的示例如下:

    database:

    addr: localhost

    port: 3306

    username: testuser

    password: abcdef

    listen:80

    复制代码

    ini

    ini 文件也是一个比较常见的配置文件的格式,也是几乎不需要学习成本的,比较简单,只有两个概念

    区块与键值对, 但表达能力比较有限,格式如下:

    [database]

    addr = localhost

    port = 3306

    [web]

    listen = 80

    复制代码

    json

    json 是一种非常流行的描述语言,表述能力也非常强,非常直观,通常也是不需要什么学习成本的,

    常见的格式如下:

    {

    "database":{

    "database":"localhost",

    "port":3306

    },

    "web":{

    "listen":80

    }

    }

    复制代码

    properties

    properties 文件对于很多Java程序员应该不陌生,因为在很多spring项目中, 会经常见到这种文件,当然没有用到过的夜别打我,这种完全看兴趣爱好的, 一个简单的文件格式如下:

    addr=localhost

    port=3306

    复制代码

    Golang 的配置文件

    golang 项目为什么要配置文件

    对于很多配置相关的项如监听的端口、数据库的地址、端口等会比较适合放在配置中,而不是硬编码在代码中,因此配置文件的使用还是比较常见的。

    对于使用什么类型的配置文件大家不需要纠结,根据需求就好了,

    配置文件需要应对的几种场景

    IDE运行/调试时期读取配置文件

    运行单测或者benchmark Test的时候读取配置文件

    可执行文件(部署文件)读取配置文件

    项目中需要仅使用一个配置文件,配置文件可以在以上三种情况下都可以被正常读取

    配置文件的放置

    一般配置文件会放在项目的根目录或者比较明显的位置,当然对于Golang我个人还是比较推荐放在项目的根目录, 当然放在其他目录也不是不可以,但可能比较麻烦。

    怎么满足配置文件需要应对的几种场景?

    从项目可执行文件目录读取配置文件, 实例代码如下:

    // get config file from where the executables lies

    func getConfigFileFromExecutable(fileName string) *os.File {

    dir, err := filepath.Abs(filepath.Dir(os.Args[0]))

    if err != nil {

    return nil

    }

    f, err := os.Open(path.Join(dir, fileName))

    if err != nil {

    return nil

    }

    return f

    }

    复制代码从源代码文件所在目录递归往上层目录寻找

    // read config file

    func TestReadConfigFile(t *testing.T) {

    if _, fileNameWithPath, _, ok := runtime.Caller(1); ok {

    d := ReadConfigFile(testFileName, fileNameWithPath)

    if d == nil {

    t.FailNow()

    }

    }

    }

    复制代码

    这个实现的关键点在于 runtime.Caller(1), 此函数可以返回源代码所在目录,但根据参数的不同,对于调用的位置要求也不同,这里设置的刚好可以满足放在项目根目录的需求

    一个开源项目

    项目地址喜欢的话点个赞(star), 有问题的话可以提issue. 以联系我。

    获取的方式如下

    go get github.com/winjeg/goconf

    复制代码

    此项目采用go module作为依赖管理方式,但也兼容于传统的dep作为依赖管理工具

    支持的格式

    yaml格式

    ini 格式

    使用实例

    package goconf

    import (

    "strings"

    "testing"

    )

    const (

    testYmlFile = "test.yaml"

    testIniFile = "test.ini"

    host = "10.1.1.1"

    port = 3306

    testName = "tom"

    )

    type TestYmlConf struct {

    DbAddr string `yaml:"dbAddr"`

    Port int `yaml:"dbPort"`

    }

    type TestMyConf struct {

    Mysql TestIniConf `ini:"mysql"`

    Name string `ini:"name"`

    }

    type TestIniConf struct {

    Host string `ini:"host"`

    Port int `ini:"port"`

    }

    func TestYaml2Object(t *testing.T) {

    var x TestYmlConf

    err := Yaml2Object(testYmlFile, &x)

    if err != nil {

    t.FailNow()

    }

    if !strings.EqualFold(x.DbAddr, host) || x.Port != port {

    t.FailNow()

    }

    }

    func TestIni2Object(t *testing.T) {

    var x TestMyConf

    err := Ini2Object(testIniFile, &x)

    if err != nil {

    t.FailNow()

    }

    if !strings.EqualFold(x.Mysql.Host, host) || x.Mysql.Port != port || !strings.EqualFold(testName, x.Name) {

    t.FailNow()

    }

    }

    复制代码

    你只需要定义自己需要的配置结构, 指定文件名称即可正确读取到配置, 使用起来也非常简单, 推荐放在项目的根目录

    读取顺序规则

    先从可执行文件的运行目录读取配置文件

    如果读取不到则从项目的源代码所在目录读取, 如果读取不到,则递归往根目录查找,直到根目录为止

    找不到配置文件则会抛出错误,找到则不会返回任何错误

    写在最后

    golang 的配置文件处理方式或许还有很多种,所以如果大家有其他比较好的法子也可以分享出来大家一起学习一起进步. 如有任何疑问,欢迎在下方留言评论,或者到上面我项目地址中去提issue.

    此文如有转载,请勿修改原文内容.

    展开全文
  • Idea 创建Golang项目

    2021-10-12 23:41:22
    创建go项目 配置golang 命令行执行 go mod init main 执行 go run main.go

    创建go项目

    配置golang

     命令行执行

    go mod init main

     执行

    go run main.go

    展开全文
  • 使用interface重构代码,面向接口,减少重复代码项目背景需要提供节目,节目集数据的增删改查,数据库使用ES(elasticsearch)重构前 →_→本文着重强调用接口重构的思路,所以只选取读取功能作为例子数据结构type ...

    使用interface重构代码,面向接口,减少重复代码

    项目背景

    需要提供节目,节目集数据的增删改查,数据库使用ES(elasticsearch)

    重构前 →_→

    本文着重强调用接口重构的思路,所以只选取读取功能作为例子

    数据结构

    type Video struct{

    VideoID string `json:"video_id"`

    //包含很多节目的属性,如节目类型,上下线状态等

    }

    type Show struct{

    ShowID string `json:"show_id"`

    //包含很多节目集的属性,如评分,演员等

    }

    ES中对应两个index,video,show 分别对应上边的两个结构。重构前读取功能实现

    package es

    import (

    "context"

    "log"

    "encoding/json"

    "github.com/olivere/elastic"

    )

    func(video *Video) ReadVideo(videoID string){

    client,_ := elastic.NewClient(elastic.SetURL("http://127.0.0.1:19200"))

    defer client.Stop()

    if !isVideoExists(videoID){

    return

    }

    esResponse,err := client.Get().Index("video").Type("video").Id(videoID).Do(context.Background())

    if err != nil {

    log.Println("Failed to read ES data of ID:! ",videoID)

    return

    }

    json.Unmarshal(*esResponse.Source,&video)

    }

    func isVideoExists(videoID string)bool{

    client,_ := elastic.NewClient(elastic.SetURL("http://127.0.0.1:19200"))

    defer client.Stop()

    exist,_ := client.Exists().Index("video").Type("video").Id(videoID).Do(context.Background())

    if !exist{

    log.Println("video ID may be incorrect! ",videoID)

    return false

    }

    return true

    }

    func(show *Show) ReadShow(showID string){

    client,_ := elastic.NewClient(elastic.SetURL("http://127.0.0.1:19200"))

    defer client.Stop()

    if !isShowExists(showID){

    return

    }

    esResponse,err := client.Get().Index("show").Type("show").Id(showID).Do(context.Background())

    if err != nil {

    log.Println("Failed to read ES data of ID:! ",showID)

    return

    }

    json.Unmarshal(*esResponse.Source,&show)

    }

    func isShowExists(showID string)bool{

    client,_ := elastic.NewClient(elastic.SetURL("http://127.0.0.1:19200"))

    defer client.Stop()

    exist,_ := client.Exists().Index("show").Type("show").Id(showID).Do(context.Background())

    if !exist{

    log.Println("show ID may be incorrect! ",showID)

    return false

    }

    return true

    }

    重构中——分析代码结构

    优点:处理流程比较清晰(没有复杂的调用逻辑,想不清晰都难......)

    缺点:

    面向过程!导致每一个过程都需要定义新的函数来处理,读取节目需要 ReadVideo(),读取节目集需要ReadShow()。无论这个新加的功能是不是已有类似的实现可复用

    代码冗余!上边的代码有非常严重的冗余,一个是判断ID是否在ES库中,一个是读取功能的实现,除了ES的路径不同,video是 video->video->VIDEO_ID;show 则是 show->show->SHOW_ID;其余的代码基本一致

    重构中——看似可行的方案

    加一个interface类型参数,再加一个指示类型的参数,只用一个Read函数,一个isExists函数就行。

    func Read(media interface{}, mediaType, id string){

    client,_ := elastic.NewClient(elastic.SetURL("http://127.0.0.1:19200"))

    defer client.Stop()

    if !isExists(id){

    return

    }

    esResponse,err := client.Get().Index(mediaType).Type(mediaType).Id(id).Do(context.Background())

    if err != nil {

    log.Println("Failed to read ES data of ID:! ",id)

    return

    }

    json.Unmarshal(*esResponse.Source,&media)

    }

    func isExists(mediaType, id string)bool{

    client,_ := elastic.NewClient(elastic.SetURL("http://127.0.0.1:19200"))

    defer client.Stop()

    exist,_ := client.Exists().Index(mediaType).Type(mediaType).Id(id).Do(context.Background())

    if !exist{

    log.Println("ID may be incorrect! ",id)

    return false

    }

    return true

    }

    原因 为什么说这是一个看似可行的方案呢?

    增加了参数个数,Read增加了两个,isExists增加了一个。一个函数的参数自然是越少越好。增加参数,差评+1

    程序的健壮性降低了!一旦mediaType没有准确地对应ID,程序就不能正常工作,比如传了 "video" 和show 的ID ,要在ES的video数据库里边找show数据库的ID,自然就会失败。另外,使用interface类型参数,同样也会造成健壮性的降低

    使用了interface类型参数。为了能够传入自定义的Show类型和Video类型数据,使用了interface。那么,在调用这个函数的时候,这个参数传int,string,bool都是合法的,但是,从实际需要的功能来说,这些参数显然是不合法的。

    总结 虽然这个实现可以减少重复代码,但是反而增加了函数调用的风险,一旦你离职,别人接手你的代码,这就会成为别人的灾难。程序的健壮性降低了,显然,这个交换并不划算!那么,有没有什么办法既能减少冗余代码,又能不带来其他的负面影响,诸如降低代码健壮性?

    重构后 ヽ( ̄▽ ̄)ノ

    很多人会问golang是不是一个面向对象的语言,论坛上的答案很玄妙:是也不是。说不是,是因为go里边没有明确的语法声明类,说是,是因为go也可以通过struct和interface实现面向对象的特性。How?请看重构之后的代码!

    package es

    import (

    "context"

    "log"

    "encoding/json"

    "github.com/olivere/elastic"

    )

    type Video struct{

    VideoID string `json:"video_id"`

    //包含很多节目的其他属性,如节目类型,上下线状态等,此处省略

    }

    type Show struct{

    ShowID string `json:"show_id"`

    //包含很多节目集的其他属性,如评分,演员等,此处省略

    }

    func(video *Video) read(videoID string){}

    func(show *Show) read(showID string){}

    type reader interface {

    read()

    }

    type esPath struct{

    ESIndex string

    ESType string

    ESID string

    }

    func Read(reader reader,esPath *esPath){

    client ,_:= ESClient()

    defer client.Stop()

    if !isExists(esPath){

    return

    }

    esResponse,err := client.

    Get().Index(esPath.ESIndex).Type(esPath.ESType).Id(esPath.ESID).Do(context.Background())

    if err != nil {

    logger.LogPrintln("Failed to read ES data of ID:! ",esPath.ESID)

    return

    }

    json.Unmarshal(*esResponse.Source,&reader)

    }

    func isExists(esPath *esPath)bool{

    client,_ := ESClient()

    defer client.Stop()

    exist,_ := client.Exists().Index(esPath.ESIndex).Type(esPath.ESType).Id(esPath.ESID).Do(context.Background())

    if !exist{

    logger.LogPrintln("ShowID may be incorrect! ",esPath.ESID)

    return false

    }

    return true

    }

    简单说明一下为何定义了一个新struct esPath,完整的程序还有修改,新增,删除等功能,可以复用这个结构。

    video和show都有read函数,所以实现了reader接口。在调用Read函数的时候只能使用show或者video类型,否则会报类型错误。避免了interface类型什么数都能瞎传的问题。在某种程度上,可以说video和show是reader类的对象,都可以用Read()函数读出reader类的对象。使用接口能够大大减少代码冗余!

    有疑问加站长微信联系(非本文作者)

    展开全文
  • 网上搜了一下,非常简单,但是坑亦然是有的.这个坑不是和go 无关,和windows 有关. 首先明确你是在cmd的模式下还是Poweshell 下编译,因为如果不区分,将导致出现错误.这个错误就是编译成功了,但是考到Centos下不执行. ...

    网上搜了一下,非常简单,但是坑亦然是有的.这个坑和go 无关,和windows 有关.
    首先明确你是在cmd的模式下还是Poweshell 下编译,因为如果不区分,将导致出现错误.这个错误就是编译成功了,但是考到Centos下不执行.
    CMD下的命令方式

    set GOOS=linux
    set GOARCH=amd64
    go build -o appName
    

    powershell 下

    $Env:GOOS="linux"
    $Env:GOARCH="amd64"
    go build -o appName
    

    说明powersh 下的环境变量修改方法不能使用 set 方式,系统没有提示错误,但是并不生效,这是个坑.
    另外,后面的值用引号引起来,并且区分大小写.

    后面的工作就是拷贝到Centos , 并设置权限.

    chmod 777 appName
    ./appName
    

    即可.

    maraSun ,2021-11-20 BJ FW area.

    展开全文
  • Ubuntu+docker+docker-compose部署golang项目(源码)编写DockerfileDockerfile内容打包镜像编写docker-compose.yamldocker-compose.yaml内容启动容器 阅读本文的前提是你已经在Ubuntu中正确安装了docker和docker-...
  • 本文jenkins部署golang项目流程 jenkins服务拉取github上的项目 构建golang项目并生成docker镜像[jenkins调用的是宿主机上的docker环境,如何调用的,后面会说明] 启动golang项目的docker镜像 docker的安装这里就...
  • Golang项目实战(一)后端分页处理 目录Golang项目实战(一)后端分页处理背景实现测试 背景 分页:根据设定页码及页面容量展示数据。简单来说,就是点击页码,例如1,即返回10条(容量)数据。 web项目开发经常需要...
  • Ubuntu+docker+docker-compose部署golang项目(可执行程序)编写DockerfileDockerfile内容打包镜像编写docker-compose.yamldocker-compose.yaml内容启动容器 阅读本文的前提是你已经在Ubuntu中正确安装了docker和...
  • Golang 项目部署

    2021-07-30 14:49:55
    注:本教程不包含golang编译部分,请自行编译;项目使用supervisor进行部署。 安装epel(已安装可以忽略) yum install epel-release 安装supervisor Supervisor是用Python开发的一套通用的进程管理程序,...
  • package lib import ( "fmt" l4g "github.com/alecthomas/log4go" "github.com/astaxie/beego/config" "os" "path/filepath" "strconv" "strings" ) const ( DEBUG = "debug" ... CRITICAL = "critic
  • Golang项目如何引用一个第三方的库?写好test.go文件后执行go run test.go的时候报错,其实是因为golang配置或者自己的项目没有配置正确。 1、首先,安装完Golang之后,需要配置一些系统变量,就像Java一样【这点...
  • 尝试用vscode来做golang开发,使用了go mod方式来管理各个包,发现vscode并不好用,F12无法跳转到,提示找不到定义,并且在右下角也会有来自Go扩展的错误提示通知: Error loading workspace: You are working in a ...
  • 通过Git上传golang项目大概步骤 1.拉取项目 第一步,先从GitLab或GitHub上将project通过git clone的方式拉下来。 首先,先在本机电脑上的GOPATH路径下创建src文件夹,再在src文件夹下创建一个文件夹,一般命名为git....
  • 寻找 Golang 开源项目学习目的可能是: 想学习或者提高自己对 Go 项目的组织和编排能力; 想学习 Go 项目的框架设计; 想在一些 Go 语法上细节的优化和进阶。 我推荐两个项目: 一、tinode 这是一个开源的即时...
  • golang项目后端测评

    2021-01-22 10:30:51
    任何项目测试帐号未经许可,不可外传(项目组范围内) 一.使用for 循环对两个切片赋值,并合并这两个切片 import "fmt" func main() { var s []int for i :=1;i<=50;i++{ s = append(s, i) } fmt.Println...
  • DockerDcoker的介绍Docker的特点Docker和虚拟机的区别Docker部署项目完整过程 Dcoker的介绍 Docker是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。 Docker可以让开发者打包自己的项目以及...
  • GoLand编辑器断点调试容器里面的golang项目 GoLand启动远程调试 服务端执行对应的项目,./user-base是项目build出来的二进制文件 dlv --headless --listen=:2345 --api-version=2 exec ./user-base 触发到断点后...
  • GoWeb之Gin项目脚手架搭建 一、Gin框架简单使用 Gin项目地址:https://github.com/gin-gonic/gin 文档地址:https://www.kancloud.cn/shuangdeyu/gin_book/949411(看云手册)和https://gin-gonic.com/zh-cn/docs/...
  • 使用golang开发项目demo

    2021-08-29 16:33:24
    使用go语言开发项目的现状 很多公司都是使用go语言来开发程序,但是开发中以及最终交付的代码需要满足以下条件: 能满足DevOps要求,对于开发来说,需要提供一个构建脚本(build.sh)即可 内网也能编译,即build.sh能...
  • Golang sync包提供了基础的异步操作方法,包括互斥锁Mutex,执行一次Once和并发等待组WaitGroup。 本文主要介绍sync包提供的这些功能的基本使用方法。 WaitGroup:并发等待组 Mutex: 互斥锁 RWMutex:读写锁 Once:...
  • package main import "fmt" func main(){ var conf config = Build...//项目中配置文件的写法 type config struct{ a int b string } func BuildConfig(ops ...Option) config { var c config = config{ .
  • 自己写了一个golang web、rpc框架,未来想做成一个微服务,公司内部使用,地址https://github.com/yanchendage/ty。 把代码提交到github 打tag git tag v0.0.2 push tag git push origin v0.0.2 go get 代码地址 go...
  • go module可以将某个项目(文件夹)下的所有依赖整理成一个 go.mod 文件,里面写入了依赖的版本等 开启go module set GO111MODULE=on //windows export GO111MODULE=on //linux goland需要在工具里另行配置,...
  • 最下面是一个叫 A 项目的 go.mod,两个 common 模块是需要指向本地的文件夹中的,这就意味着,换了其他环节编译这个 A 项目的时候,你必须在上层文件夹目录提前下载好两个 common 项目,这就不太标准了,比较好的...
  • Docker部署Golang项目及镜像优化实战 今天在部署公司的项目时, 了解到目标服务器有Docker环境,于是就想着基于Docker来部署项目 这篇文章记录了一次完整的构建镜像到优化的完整过程. 基础环境 Docker Windows10 ...
  • 当使用PProf不是太详细的时候就可以使用 trace来查看跟踪了 这个命令可以配合PProf 先把trace文件下载下来 ...seconds=20 > trace.out 使用 go tool trace C:\Users\shihan1\Downloads\trace.out ...
  • 一、Golang项目简单介绍 Golang简单的目录结构如下: 其中,bin用来存放经过go bulid后的可执行文件,pkg存放编译后的go module,而src就存放我们项目的代码 二、三种常用目录结构 1、适合个人开发者 2、流行...
  • GitHub - wuyan94zl/go-cache: distributed cache running in project 在项目中运行的分布式缓存distributed cache running in project 在项目中运行的分布式缓存. Contribute to wuyan94zl/go-cache development by...
  • port/用户名/$项目.git 拉取仓库内容 git pull origin test --allow-unrelated-histories 提交项目 git-add git-commit git-repository-push 删除文件夹 git rm --cached -r .idea 修改分支 切换到master分支 git ...
  • Ubuntu Golang项目编译报错 cgo: exec gcc: exec: "gcc": executable file not found in $PATH 这个问题原因是项目内有引用c的库. golang在使用cgo调用c的库. 所以是cgo报的错. 解决方法: 安装gcc就行 sudo ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 41,252
精华内容 16,500
关键字:

golang项目