ACChe

ACChe 查看完整档案

广州编辑  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑

举头思算法,低头写代码...

个人动态

ACChe 提出了问题 · 2016-06-24

[Go]怎么获得访问者的时区来将对应的时间转换成访问者的时区时间来显示?

想根据访问者的时区来将格式化显示时间来适应不同地方的访问,应该怎么做?

关注 2 回答 2

ACChe 赞了文章 · 2016-06-23

Baa框架中的依赖注入(DI)是个什么鬼?

我最早接触的Go WEB框架是beego,很强大的一个框架,也是很多人的首选,就是因为太(bu)强(gou)大(ling)了(huo),后来尝试了Macaron(martini)。Macaron的设计是众多框架的主流思想,路由、中间件、HTTP上下文,然后自己实现了一些常用的中间件(PS. 有一些中间件代码来自beego)。Macaron的思想中,可以通过m.Map()注入任意类型,然后在Context中通过反射获取这个类型,初试很爽,并为他的设计称赞。

在用PHP的时候有个框架 Phalcon他的设计中核心是 Dependency Injection/Service Location,看起来很复杂,简单来说就是把类似log,db,cache,metadata等服务注册到DI中,使用的时候从DI取出来。Phalcon的使用姿势中就是先初始化一个APP,然后各种注册DI,然后RUN,伪代码如下:

<?php

$di = new \Phalcon\DI\FactoryDefault();
$di->set('router', new MyRouter());
$di->set('logger', function () {
    return new LoggerFile('../apps/logs/error.log');
});
$di->set('db', function () {
    return new PdoMysql(
        array(
            "host"     => "localhost",
            "username" => "root",
            "password" => "secret",
            "dbname"   => "blog"
        )
    );
});
$di->set('db2', ...);
$di->set('mongo', new \MongoClient());

// Create an application
$application = new \Phalcon\Mvc\Application($di);

// Handle the request
echo $application->handle()->getContent();

上面的初始化,就是各种set,当然他支持set的类型比较丰富,还支持lazyload等,使用的方式也比较简单:

<?php

$di = new \Phalcon\DI\FactoryDefault();
$db = $di->get('db');
$mongo = $di->get('mongo');
$mongo->selectCollection('xxx');

总结下来,就是 set/get,set就是设置一个服务(注入),get就是取出这个服务来使用,当然php不像Go是静态语言,他不需要做类型断言。

介绍完背景,其实也问题也基本明确了,在使用macaron的过程中,过分依赖反射,导致同一种类型只能注册一个,比如我要两个db,两个logger类型一致但做不同的服务用途,就比较难了。其实我最痛苦的是logger,macaron框架中使用了原声的log包,我无论怎么写都做不到日志统一,框架中输出的日志不依赖注入,就是原生的log。结合我对Phalcon的经验,就萌生了把Phalon DI的思想移植过来的念头,再结合其他想法,就去做了Baa。DI是Baa中目前写得最简单的东西,但是却是最直接导致去造轮子的。

再来看Baa的DI思想特别简单,就是一个set一个get,使用姿势和Phalcon也一样,只不过目前没有提供那么多姿势的支持,比如懒加载(匿名函数)在调用时初始化,静态类就是set一个字符串使用的时候去new。虽然简单,但思想并无差别。我们可以做个示例:

package main

import (
    "github.com/go-baa/cache"
    _ "github.com/go-baa/cache/redis"
    "github.com/go-baa/render"
    "gopkg.in/baa.v1"
)

func main() {
    // new app
    app := baa.New()
    
    // register logger
    app.SetDI("logger", log.Logger)
    
    // register render
    b.SetDI("render", render.New(render.Options{
        Baa:        app,
        Root:       "templates/",
        Extensions: []string{".html", ".tmpl"},
        FuncMap:    template.Funcs(b),
    }))

    // register cache
    app.SetDI("cache", cache.New(cache.Options{
        Name:     "cache",
        Prefix:   "MyApp",
        Adapter:  "memory",
        Config:   map[string]string{},
    }))
    app.SetDI("cache2", cache.New(cache.Options{
        Name:     "cache2",
        Prefix:   "MyApp2",
        Adapter:  "redis",
        Config:   map[string]string{},
    }))

    // router
    app.Get("/", func(c *baa.Context) {
        ca := c.DI("cache").(cache.Cacher)
        ca.Set("test", "baa", 10)
        v := ca.Get("test").(string)
        c.String(200, v)
    })

    // run app
    app.Run(":1323")
}

在app的初始化中通过set我们注入logger,render,cacher,甚至db的初始化等,在需要的地方比如Context中,context.DI()来获取,或者在其他地方可以 baa.Default().GetDI()来获取使用。再看我上面吐槽的log,在这里你只要app.SetDI("logger", xxx)即可以替换掉框架内置的logger,render也一样,只要注册一个实现了baa.Renderer接口的render就可以自定义模板引擎。

依赖注入(DI)不是什么玩意,虽然只有几行代码,但他是一种设计思想,一种理念,一种解决问题的姿势。

查看原文

赞 4 收藏 11 评论 0

ACChe 赞了回答 · 2016-06-19

golang用啥IDE

vscode 你值得拥有,配合go插件非常棒

关注 28 回答 25

ACChe 提出了问题 · 2016-06-19

解决Beego的Router在本地跑正常,搬上服务器后出现notmatch

// Test.go
package controllers

import (
    "models"
    "github.com/astaxie/beego"
)

type TestController struct {
    beego.Controller
}

// Get ...
func (c *TestController) Get() {
    testList := models.GetTestList()
    c.Data["testList"] = testList

    c.TplName = "test/index.html"

}
// Router.go
package routers

import (
    "nav/controllers"

    "github.com/astaxie/beego"
)

func init() {
    beego.AutoRouter(&controllers.TestController{})

    beego.Router("/test", &controllers.TestController{})
}
// main.html
<li><a href="/test"><font color="black">TEST</font></a></li>

在本地(Mac OS)上跑可以点击跳转打开,放到服务器后打开会404,log显示notmatch,其他链接正常match到.

这是什么原因呢?求答案!

关注 1 回答 1

ACChe 赞了回答 · 2016-06-12

京东iOS ,APP 热更新是怎么实现的?

所有的图片都是在线获取离线到本地的吧,服务端换了,自然就更新了。热更新肯定是在线索取图片。
图片描述

关注 12 回答 5

ACChe 赞了回答 · 2016-06-12

京东iOS ,APP 热更新是怎么实现的?

楼上的抓包已经很明显了
jd的这些图片可以每一次去获取
反正不涉及逻辑
如果涉及逻辑可以用JSPatch这些东西

关注 12 回答 5

ACChe 提出了问题 · 2016-06-12

Beego里的with … end用法没有看懂?

Beego里的模版语法有一个:

with … end

{{with pipeline}}{{end}}
with 用于重定向 pipeline

{{with .Field.NestField.SubField}}
    {{.Var}}
{{end}}
也可以对变量赋值操作

{{with $value := "My name is %s"}}
    {{printf . "slene"}}
{{end}}
with 也支持 else

{{with pipeline}}
{{else}}
    {{/* 当 pipeline 为空时会执行这里 */}}
{{end}}

它是循环还是什么?

关注 1 回答 0

ACChe 赞了问题 · 2016-06-12

解决求一些golang的教程,书籍也可以

想学一下golang,求一些教程,书籍也可以

关注 10 回答 7

ACChe 提出了问题 · 2016-06-06

解决Golang里http请求是在哪里添加X-Auth-Token?

Golang里http请求是在哪里添加X-Auth-Token?

关注 2 回答 1

ACChe 赞了文章 · 2016-06-06

Go 语言从新手到大神:每个人都会踩的五十个坑 (1-12)

本文翻译自最近各种 Go 语言社区分享的很多的英文文档 50 Shades of Go: Traps, Gotchas, and Common Mistakes for New Golang Devs,小编第一眼以为 50 Shades of Grey……

Go语言是一个简单却蕴含深意的语言。但是,即便号称是最简单的C语言,都能总结出一本《C陷阱与缺陷》,更何况Go语言呢。Go语言中的许多坑其实并不是因为Go自身的问题。一些错误你再别的语言中也会犯,例如作用域,一些错误就是对因为 Go 语言的特性不了解而导致的,例如 range。

其实如果你在学习Go语言的时候去认真地阅读官方文档,百科,邮件列表或者其他的类似 Rob Pike 的名人博客,报告,那么本文中提到的许多坑都可以避免。但是不是每个人都会从基础学起,例如译者就喜欢简单粗暴地直接用Go语言写程序。如果你也像译者一样,那么你应该读一下这篇文章:这样可以避免在调试程序时浪费过多时间。

本文将50个坑按照使用使用范围和难易程度分为以下三个级别:“新手入门级”,“新手深入级”,“新手进阶级”。

“{”不能单独放在一行

级别:新手入门级

Go语言设计者肯定和C语言设计者(K&R)有种不明不白的关系,因为C语言中的K&R格式在Go语言中得到发扬光大。大多数语言中,大括号中的左括号是可以随便放在哪里的:C语言中必须要按照K&R格式对代码进行格式化之后,左括号才会被放在前一行中的最后。但是Go语言中,左括号必须强制不能单独放在一行。这个规则得益于“自动分号注射”(automatic semicolon injection)。

补充:go提供了专门用于格式化代码的gofmt工具。

出错代码:

package main

import "fmt"

func main()  
{ //error, can't have the opening brace on a separate line
    fmt.Println("hello there!")
}

错误信息:

/tmp/sandbox826898458/main.go:6: syntax error: unexpected semicolon or newline before {

修正代码:

package main

import "fmt"

func main() {  
    fmt.Println("works!")
}

未使用已定义的变量

级别:新手入门级

如果代码中有未使用的变量,那个代码编译的时候就会报错。Go要求在代码中所有声明的变量都需要被用到,当然,全局变量除外。
函数的参数也可以只被声明,不被使用。

对于未声明变量的调用同样会导致编译失败。和C语言一样,Go编译器也是个女人,他说什么你都要尽力满足。

出错代码:

package main

var gvar int //not an error

func main() {  
    var one int   //error, unused variable
    two := 2      //error, unused variable
    var three int //error, even though it's assigned 3 on the next line
    three = 3

    func(unused string) {
        fmt.Println("Unused arg. No compile error")
    }("what?")
}

错误信息:

/tmp/sandbox473116179/main.go:6: one declared and not used /tmp/sandbox473116179/main.go:7: two declared and not used /tmp/sandbox473116179/main.go:8: three declared and not used

修正代码:

package main

import "fmt"

func main() {  
    var one int
    _ = one

    two := 2 
    fmt.Println(two)

    var three int 
    three = 3
    one = three

    var four int
    four = four
}

当然,你也可以考虑删除那些没有使用的变量。

未使用的包

级别:新手入门级

当import一个包之后,如果不使用这个包,或者这个包中的函数/接口/数据结构/变量,那么将会编译失败。

如果真的确认要引入变量但是不使用的话,我们可以用“”标识符坐标记,避免编译失败。“”标识符表示为了得到这些包的副作用而引入这些包。

出错代码:

package main

import (  
    "fmt"
    "log"
    "time"
)

func main() {  
}

错误信息:

/tmp/sandbox627475386/main.go:4: imported and not used: "fmt" 
/tmp/sandbox627475386/main.go:5: imported and not used: "log" 
/tmp/sandbox627475386/main.go:6: imported and not used: "time"

修正代码

package main

import (  
    _ "fmt"
    "log"
    "time"
)

var _ = log.Println

func main() {  
    _ = time.Now
}

只能在函数内部使用简短的变量声明

级别:新手入门级
出错代码:

package main

myvar := 1 //error

func main() {  
}

错误信息:

/tmp/sandbox265716165/main.go:3: non-declaration statement outside function body

修正代码:

package main

var myvar = 1

func main() {  
}

无法使用精简的赋值语句对变量重新赋值

级别:新手入门级

不能使用精简的赋值语句重新赋值单个变量,但是可以使用精简的赋值语句同时赋值多个变量。

并且,重定义的变量必须写在同一个代码块。

错误信息:

package main

func main() {  
    one := 0
    one := 1 //error
}

错误信息:

/tmp/sandbox706333626/main.go:5: no new variables on left side of :=

修正代码:

package main

func main() {  
    one := 0
    one, two := 1,2

    one,two = two,one
}

隐式变量(作用域)

级别:新手入门级

和 C 语言一样,Go 语言也有作用于,一个变量的作用范围仅仅是一个代码块。虽然精简的赋值语句很简单,但是注意作用域。

package main

import "fmt"

func main() {  
    x := 1
    fmt.Println(x)     //打印 1
    {
        fmt.Println(x) //打印 1
        x := 2
        fmt.Println(x) //打印 2
    }
    fmt.Println(x)     //打印 1 ( 不是 2)
}

甚至对于有经验的开发者来说,这也是个不注意就会掉进去的深坑。

除非特别指定,否则无法使用 nil 对变量赋值

级别:新手入门级

nil 可以用作 interface、function、pointer、map、slice 和 channel 的“空值”。但是如果不特别指定的话,Go 语言不能识别类型,所以会报错。

错误信息:

package main

func main() {  
    var x = nil //error

    _ = x
}

错误信息:

/tmp/sandbox188239583/main.go:4: use of untyped nil

修正代码:

package main

func main() {  
    var x interface{} = nil

    _ = x
}

Slice 和 Map 的 nil 值

级别:新手入门级

初始值为 nil 的 Slice 是可以进行“添加”操作的,但是对于 Map 的“添加”操作会导致运行时恐慌。( ﹁ ﹁ ) 恐慌。

修正代码:

package main

func main() {  
    var s []int
    s = append(s,1)
}

错误信息:

package main

func main() {  
    var m map[string]int
    m["one"] = 1 //error

}

Map 定长

级别:新手入门级

创建 Map 的时候可以指定 Map 的长度,但是在运行时是无法使用 cap() 功能重新指定 Map 的大小,Map 是定长的。

错误信息:

package main

func main() {  
    m := make(map[string]int,99)
    cap(m) //error
}

错误信息:

/tmp/sandbox326543983/main.go:5: invalid argument m (type map[string]int) for cap

字符串无法为 nil

级别:新手入门级

所有的开发者都可能踩的坑,在 C 语言中是可以 char *String=NULL,但是 Go 语言中就无法赋值为 nil。

错误信息:

package main

func main() {  
    var x string = nil //error

    if x == nil { //error
        x = "default"
    }
}

Compile Errors:

/tmp/sandbox630560459/main.go:4: cannot use nil as type string in assignment /tmp/sandbox630560459/main.go:6: invalid operation: x == nil (mismatched types string and nil)

修正代码:

package main

func main() {  
    var x string //defaults to "" (zero value)

    if x == "" {
        x = "default"
    }
}

参数中的数组

Array Function Arguments

级别:新手入门级
对于 C 和 C++ 开发者来说,数组就是指针。给函数传递数组就是传递内存地址,对数组的修改就是对原地址数据的修改。但是 Go 语言中,传递的数组不是内存地址,而是原数组的拷贝,所以是无法通过传递数组的方法去修改原地址的数据的。

package main

import "fmt"

func main() {  
    x := [3]int{1,2,3}

    func(arr [3]int) {
        arr[0] = 7
        fmt.Println(arr) //prints [7 2 3]
    }(x)

    fmt.Println(x) //prints [1 2 3] (not ok if you need [7 2 3])
}

如果需要修改原数组的数据,需要使用数组指针(array pointer)。

package main

import "fmt"

func main() {  
    x := [3]int{1,2,3}

    func(arr *[3]int) {
        (*arr)[0] = 7
        fmt.Println(arr) //prints &[7 2 3]
    }(&x)

    fmt.Println(x) //prints [7 2 3]
}

或者可以使用 Slice,

package main

import "fmt"

func main() {  
    x := []int{1,2,3}

    func(arr []int) {
        arr[0] = 7
        fmt.Println(arr) //prints [7 2 3]
    }(x)

    fmt.Println(x) //prints [7 2 3]
}

使用 Slice 和 Array 的 range 会导致预料外的结果

级别:新手入门级

如果你对别的语言中的 for inforeach 熟悉的话,那么 Go 中的 range 使用方法完全不一样。因为每次的 range 都会返回两个值,第一个值是在 Slice 和 Array 中的编号,第二个是对应的数据。

出错代码:

package main

import "fmt"

func main() {  
    x := []string{"a","b","c"}

    for v := range x {
        fmt.Println(v) //prints 0, 1, 2
    }
}

修正代码:

package main

import "fmt"

func main() {  
    x := []string{"a","b","c"}

    for _, v := range x {
        fmt.Println(v) //prints a, b, c
    }
}

( ﹁ ﹁ ) 怎么有“大神”这个标签……
本文续集会在今晚八点前发布,敬请期待。

查看原文

赞 20 收藏 135 评论 11

ACChe 关注了问题 · 2016-05-23

GO语言中请问为什么不能直接访问一个Strut的方法?

func main() {
    t := test // 如果这里改成 t:=new(test)就可以执行了
    t.Name = "ACE"
    t.test()
}

type test struct {
    Name string
}

func (this test) test() {
    fmt.Println(this.Name)
}

为什么这样写会报错?
command-line-arguments
./main.go:14: type test is not an expression
是因为没有实例化的原因么?如果不用new(不实例化), 怎么直接能调用到test?

关注 5 回答 3

ACChe 关注了问题 · 2016-05-23

解决Gopher 是什么意思?

GOPHER CHINA 大会 http://gopherchina.org/
这个 Gopher 是什么意思?

应该不是维基百科里所说的那个 Gopher https://zh.wikipedia.org/wiki/Gopher_(%E7%BD%91%E7%BB%9C%E5%8D%8F%E8%AE%AE)

感觉上 应该类似 PHPer 的意义?
Gopher 直译是 地鼠,
Gopher 是 Golang 程序员的昵称吗?

关注 4 回答 1

ACChe 关注了问题 · 2016-05-23

解决多年oop开发经验的人 如何去理解redux这类函数式的东西

学习react不长 但对flux redux这类函数式的思想 属实不理解 你让我理解mvc ioc aop 都特别容易 搞了多年java我是不是被洗脑了??

关注 5 回答 1

ACChe 关注了问题 · 2016-05-23

解决面向过程编程和函数式编程有什么区别?

不理解函数式编程。求解。

更新:

个人理解:“面向过程”和“面向对象”的区别是“封装”。“函数式”和“面向对象”的区别是“不使用外部状态”。 这三种编程思想真是云里雾里。

关注 23 回答 8

ACChe 提出了问题 · 2016-05-20

[Golang]如何写一个通用的方法去请求不同格式的URL

www.xxx.com/test
www.xxx.com/check/1111?Authorization=xxxxxxx
www.xxx.com/orders?id=123&Authorization=xxxxxxx&data=20121212
...
...
...
(很多类似的url)

能不能用一个通用的方法去请求不同格式的URL,应该用什么样的方式去封装参数传到方法里?

关注 5 回答 3

ACChe 关注了问题 · 2016-05-10

关于DefaultServeMux源码这一块没看懂,请高手解释一下

func NewServeMux() *ServeMux { return new(ServeMux) }
// DefaultServeMux is the default ServeMux used by Serve.
var DefaultServeMux = &defaultServeMux
var defaultServeMux ServeMux

这一块中defaultServeMux变量声明后没有初始化吧?DefaultServeMux获得的是?在网上看别人分析的源码经常看到var DefaultServeMux = NewServeMux(),但是我在
https://sourcegraph.com/github.com/golan...
看到的是我贴出来的这段代码,并没有调用NewServe(),这里实在是不明白。
看了下历史版本这个写法是1.6 master 分支看到的。

关注 3 回答 1

ACChe 赞了问题 · 2016-05-10

解决golang - 解析复杂json

代码在这里 http://play.golang.org/p/l1__b2FOsv

// Click here and start typing.
package main

import "fmt"
import "encoding/json"

type MxRecords struct {
    value    string
    ttl      int
    priority int
    hostName string
}

type Data struct {
    mxRecords []MxRecords
}

type Response struct {
    Status string `json:"status"`
    Data   Data `json:"data"`
}
type apiR struct {
    Response Response `json:"response"`
}

func main() {

    body := `
  {"response": {
  "status": "SUCCESS",
  "data": {
    "mxRecords": [
      {
        "value": "us2.mx3.mailhostbox.com.",
        "ttl": 1,
        "priority": 100,
        "hostName": "@"
      },
      {
        "value": "us2.mx1.mailhostbox.com.",
        "ttl": 1,
        "priority": 100,
        "hostName": "@"
      },
      {
        "value": "us2.mx2.mailhostbox.com.",
        "ttl": 1,
        "priority": 100,
        "hostName": "@"
      }
    ],
    "cnameRecords": [
      {
        "aliasHost": "pop.a.co.uk.",
        "canonicalHost": "us2.pop.mailhostbox.com."
      },
      {
        "aliasHost": "webmail.a.co.uk.",
        "canonicalHost": "us2.webmail.mailhostbox.com."
      },
      {
        "aliasHost": "smtp.a.co.uk.",
        "canonicalHost": "us2.smtp.mailhostbox.com."
      },
      {
        "aliasHost": "imap.a.co.uk.",
        "canonicalHost": "us2.imap.mailhostbox.com."
      }
    ],
    "dkimTxtRecord": {
      "domainname": "20a19._domainkey.a.co.uk",
      "value": "\"v=DKIM1; g=*; k=rsa; p=DkfbhO8Oyy0E1WyUWwIDAQAB\"",
      "ttl": 1
    },
    "spfTxtRecord": {
      "domainname": "a.co.uk",
      "value": "\"v=spf1 redirect=_spf.mailhostbox.com\"",
      "ttl": 1
    },
    "loginUrl": "us2.cp.mailhostbox.com"
  }
}}`

    var r apiR
    err := json.Unmarshal([]byte(body), &r)
    if err != nil {
        fmt.Printf("err was %v", err)
    }

    fmt.Println(r)

}

解析出来data为空,这是为何?
不用interface该如何解析

关注 1 回答 3

ACChe 提出了问题 · 2016-05-10

Go如何通用的处理请求回来的json数据?

有好几个API,返回的是json格式。根据返回的JSON格式做了几个不同的struct,想写一个通用的请求方法,可以返回对应的自定义类型的变量,应该怎么做?

关注 12 回答 7

ACChe 赞了回答 · 2016-05-09

解决url拼接有没有函数可以直接完成的?

$data  = array( 'foo' => 'bar' ,
               'baz' => 'boom' ,
               'cow' => 'milk' ,
               'php' => 'hypertext processor' );

echo  http_build_query ( $data )  ;
//foo=bar&baz=boom&cow=milk&php=hypertext+processor

关注 3 回答 1

ACChe 赞了问题 · 2016-05-09

解决url拼接有没有函数可以直接完成的?

array(
'url' => '111',
'desc' => '123',
'type' => 'share',
'showcount' => '',
);
转换成:
url=111&desc=123&type=share&showcount=

关注 3 回答 1