map映射到结构体,这里只支持简单的数据类型,复杂的需要在拓展

package main
import (
    "errors"
    "fmt"
    "reflect"
    "strconv"
    "time"
)
type User struct {
    Name string
    Age  int8
    Date time.Time
}
func main() {
    data := make(map[string]interface{})
    data["Name"] = "张三"
    data["Age"] = 26
    data["Date"] = "2015-09-29 00:00:00"
    result := &User{}
    err := FillStruct(data, result)
    fmt.Println(err, fmt.Sprintf("%+v", *result))
}
//用map填充结构
func FillStruct(data map[string]interface{}, obj interface{}) error {
    for k, v := range data {
        err := SetField(obj, k, v)
        if err != nil {
            return err
        }
    }
    return nil
}
//用map的值替换结构的值
func SetField(obj interface{}, name string, value interface{}) error {
    structValue := reflect.ValueOf(obj).Elem()        //结构体属性值
    structFieldValue := structValue.FieldByName(name) //结构体单个属性值
    if !structFieldValue.IsValid() {
        return fmt.Errorf("No such field: %s in obj", name)
    }
    if !structFieldValue.CanSet() {
        return fmt.Errorf("Cannot set %s field value", name)
    }
    structFieldType := structFieldValue.Type() //结构体的类型
    val := reflect.ValueOf(value)              //map值的反射值
    var err error
    if structFieldType != val.Type() {
        val, err = TypeConversion(fmt.Sprintf("%v", value), structFieldValue.Type().Name()) //类型转换
        if err != nil {
            return err
        }
    }
    structFieldValue.Set(val)
    return nil
}
//类型转换
func TypeConversion(value string, ntype string) (reflect.Value, error) {
    if ntype == "string" {
        return reflect.ValueOf(value), nil
    } else if ntype == "time.Time" {
        t, err := time.ParseInLocation("2006-01-02 15:04:05", value, time.Local)
        return reflect.ValueOf(t), err
    } else if ntype == "Time" {
        t, err := time.ParseInLocation("2006-01-02 15:04:05", value, time.Local)
        return reflect.ValueOf(t), err
    } else if ntype == "int" {
        i, err := strconv.Atoi(value)
        return reflect.ValueOf(i), err
    } else if ntype == "int8" {
        i, err := strconv.ParseInt(value, 10, 64)
        return reflect.ValueOf(int8(i)), err
    } else if ntype == "int32" {
        i, err := strconv.ParseInt(value, 10, 64)
        return reflect.ValueOf(int64(i)), err
    } else if ntype == "int64" {
        i, err := strconv.ParseInt(value, 10, 64)
        return reflect.ValueOf(i), err
    } else if ntype == "float32" {
        i, err := strconv.ParseFloat(value, 64)
        return reflect.ValueOf(float32(i)), err
    } else if ntype == "float64" {
        i, err := strconv.ParseFloat(value, 64)
        return reflect.ValueOf(i), err
    }
    //else if .......增加其他一些类型的转换
    return reflect.ValueOf(value), errors.New("未知的类型:" + ntype)
}

习惯了php中的seek和tell,转到golang时突然发现只有Seek发现,tell方法不见了。google了一下,发现了tell的实现方法:

File.Seek(0, os.SEEK_CUR) 或者File.Seek(0,1) 参考

解释:

先来看下Seek方法

func (f *File) Seek(offset int64, whence int) (ret int64, err error)

跳转到文本中的某处,并返回此处的偏移量

File.Seek(0, os.SEEK_CUR) #跳转到当前位置(位置不变)

这样就很好理解了。

f,_:=os.Open("a.txt")
//从头开始,文件指针偏移100
f.Seek(100,0) 
buffer:=make([]byte,1024)
// Read 后文件指针也会偏移
_,err:=f.Read(buffer)
if err!=nil{
    fmt.Println(nil)
    return
}
// 获取文件指针当前位置
cur_offset,_:=f.Seek(0,os.SEEK_CUR)
fmt.Printf('current offset is %d\n', cur_offset)

虽然方便,但是使用+=操作符并不是在一个循环中往字符串末尾追加字符串最有效的方式。

一个有效的方式是准备好一个字符串切片([]string),然后使用strings.Join()函数一次性将所有字符串串联起来。

但是在go中还有一个更好的方法,其原理类似于java中的stringBuilder

package main
import (
    "bytes"
    "fmt"
)
func main() {
    var buffer bytes.Buffer //Buffer是一个实现了读写方法的可变大小的字节缓冲
    for {
        if piece, ok := getNextString(); ok {
          // Write将s的内容写入缓冲中,如必要会增加缓冲容量。返回值n为len(p),err总是nil。
          // 如果缓冲变得太大,Write会采用错误值ErrTooLarge引发panic。
            buffer.WriteString(piece)
        } else {
            break
        }
    }
    fmt.Println("拼接后的结果为-->", buffer.String())
}

转自:http://studygolang.com/articles/3427


Golang 官方的子仓库,应该使用 import "golang.org/x/net/websocket" 这种方式导入,通过 go get 方式下载。如果使用 git clone,clone下来的目录,也应该使用 src/golang.org/x/net/websocket 这样的目录,所以做法就特别蛋疼

要先

go get github.com/golang/net/websocket

然后

mv github.com/golang/net/websocket golang.org/x/net/websocket

然后import的时候用 golang.org/x/net/websocket

特别的蛋疼,难道是不想人用github上面的?因为上面的不是稳定版本


从PHP转到Golang来最烦的莫过于老得判断类型,下面总结一下类型

Golang里面获取类型可以用reflect或者fmt,现在分别试试看他们的用法

fmt.Printf("%T\n", str);

fmt.Println(reflect.TypeOf(str))

如果想把类型获取然后进行业务处理

str := fmt.Sprintf("%T\n", str)    // 获得的是字符串表示的类型

str := reflect.TypeOf(str)           // 获得的是类型

还可以定义 interface,然后通过switch配合(type)来判断

var a interface{}
a = 1
// a = "string";
switch vtype := a.(type) {
    case string:
        fmt.Println("string")
    case int:
        fmt.Println("int")
    default:
        fmt.Println(vtype)
}