Go! (Part 3) - Object

package main

import "fmt"

type User struct {
	name string
	age  int
}

func (self *User) hello() {
	fmt.Println(self.name)
}

func main() {
	p := User{"nonocast", 18}
	p.hello()
}

this的概念通过显示方式传入,传值和传引用和C是一致的。

最为关键的是interface体系,

package main

import "fmt"

type User struct {
	name string
	age  int
}

func (self *User) hello() {
	fmt.Println(self.name)
}

type IHello interface {
	hello()
}

func main() {
	var p IHello
	p = &User{"nonocast", 18}
	p.hello()
}

虽说可以通过不同的方式创建对象,看上去也没什么区别,看代码,

package main

import (
  "fmt"
  "reflect"
)

type User struct {
  name string
}

func main() {
  fmt.Println("hello world")

  var x User
  y := new(User)

  fmt.Println(reflect.TypeOf(x))  // main.User
  fmt.Println(reflect.TypeOf(y))  // *main.User
}

Go! (Part 2) - Syntax

变量

  • 大小写敏感
  • var x int = 1或x := 1,:=表示声明同时初始化变量,根据初始化对象反推x类型。
  • 支持多重赋值,i, j = j, i
  • const表示常量,和C一样,但多了一个itoa,遇到const清零,每次itoa自增1
  • 基础类型包括:bool, byte, int8, int16, int, uint, uintptr, float32, float64, complex64, complex128, string ,rune(字符), error
  • 复合类型包括:pointer, array, slice, map, chan(通道), struct, interface
  • string对中文支持很好,内部很明显采用utf8编码
    func main() {
      x := "中国"
      fmt.Println(x)
      fmt.Println(len(x)) // 6
    }
    
  • 数组:[32]byte, [3][5]int, [2][2][2]float64
    package main
    
    import "fmt"
    
    func main() {
    	var x [3]int
    	x[0] = 7
    	x[1] = 8
    	x[2] = 9
    
    	p := [3]int{7, 8, 9}
    
    	for each := range p {
    		fmt.Println(each)
    	}
    }
    
  • Go语言中和C一样区分值类型(value type)和引用类型
  • 内置的map
    package main
    
    import "fmt"
    
    func main() {
    	var x map[int]string = make(map[int]string)
    	x[0] = "aaa"
    	x[1] = "bbb"
    	x[2] = "ccc"
    
    	// another ways
    	p := map[int]string{0: "aaa", 1: "bbb", 2: "ccc"}
    
    	for k, v := range p {
    		fmt.Println(k, v)
    	}
    
    }
    

流程控制

无非就是if, switch, for goto, 对,没有while,直接跳转Golang-控制语句 - 奇语闲谭

for {
  fmt.Println("forever")
}

说实话,蛮妖怪的。

函数

  • first class, 多返回值,支持匿名和闭包
  • 最简单的函数: func x() { }
  • 最完整的函数: func x(a int, b string) (ret int, err error) { }
  • 简化: func x(a, b int) int { }, 当a,b同为int,且只有一个返回值时
  • 不定参数:func x(args ...int)
  • 匿名
    func main() {
    	x := func(p int) { fmt.Println(p) }
    	x(99)
    }
    

Go! (Part 1)

开始学习Go,首先需要明确的是Go是静态语言,就是说需要编译链接后生成可执行文件才能运行。

从hello world开始,
vi hello.go

package main

import "fmt"

func main() {
	fmt.Println("hello world")
}

直接运行,go run hello.go
编译,go build hello.go

由于Go天生跨平台所以在*nix/mac下会生成hello,./hello运行,而windows下则直接生成hello.exe,如果你跨平台用gcc就知道有多麻烦了,而且go在平台层面直接支持x86和ia64,所以你也不需要考虑这些事情。

我个人感觉Go就是一个全新的C升级版,跨平台,直接支持utf8,支持异常处理,匿名函数和lambda,简化过于灵活的指针,抽象32/64bit架构,直接支持并行,直接生成二进制,混C,你还等什么呢?

Mongodb 笔记 (Part 2)

熟悉MongoDB

  • 每个document都由一个"_id"特殊的键,这个键在此document所属的collection中是唯一的, _id不是guid,而是一个特定的ObjectId, 12字节长。
    > new ObjectId()
    ObjectId("542e39a90a9e3f862cf511cc")

    ObjectId=时间戳(4)+机器名散列(3)+PID(3)+计数器(4),所以1秒内同一进程插入的数据只有最后3位不同,如果插入的document没有_id,MongoDB会自动创建。

  • 区分类型,区分大小写。{"foo":3}和{"foo":"3"}是不同的,foo, Foo当然也是不同的。
  • document中不能出现重复key
  • collection不能以"system."开头,不能包含"$"字符
  • database-collection-document,database最终会变成文件系统里的文件,文件名就是数据库名(/data/db下并没有以数据库为名的文件,这是为什么呢?)
  • 通过mongod --rest启动内置web interface,允许rest的数据操作,见官方说明

    运行mongod --rest首先要确保关闭先前的mongod instance,进入mongo admin,然后db.shutdownServer()
  • shell(mongo)是一个javascript解释器加上mongo语法糖(db, use)等
  • Mac下开机启动通过homebrew的script参考brew info mongo, 手动启动服务,launchctl load -w ~/Library/LaunchAgents/homebrew.mxcl.mongodb.plist

使用MongoDB shell

连接远程mongodb: mongo 192.168.0.105:27017/mydb,如果需要远程连接需要关闭默认配置中的bind_ip,修改mongod.conf,注释掉bind_ip:

# Store data in /usr/local/var/mongodb instead of the default /data/db
dbpath = /usr/local/var/mongodb

# Append logs to /usr/local/var/log/mongodb/mongo.log
logpath = /usr/local/var/log/mongodb/mongo.log
logappend = true

# Only accept local connections
# bind_ip = 127.0.0.1

仅启动shell: mongo --nodb
启动后再连接,即shell内连接:

conn = new Mongo("192.168.0.105:27017")
db = conn.getDB("mydb")

可以传入javavscript给shell,

mongo script1.js script2.js script3.js

或者

mongo --quiet mydb script1.js script2.js script3.js

--quiet即重定向stdout到null
如果在shell内可以通过load("script.js")调用script, load只能处理绝对路径无法处理~。

shell启动时会默认加载.mongorc.js,通常在rc.js中放入常用函数省去每次加载的麻烦。

继续,

  • upsert等同于insert+update,如果有则update,没有则insert
  • find支持正则表达式,db.users.find({"name": /joe/i}), MongoDB的正则采用Perl的PCRE库来实现
  • 可以通过script.js来扩展mongo服务端功能,这个后期着重研究,先提一下

使用MongoDB进行开发

索引

通过db.users.ensureIndex({"name":1});建立索引,通常一个特定的collection上不应该拥有2个以上的索引,挑选合适的字段建立索引非常重要。因为索引涉及的开销包括内存以及CUD时的更新。

通过explain()来检查效率,db.users.find({"name":"user101"});

聚合

MapReduce

复制

分片

应用程序管理

服务器管理

参考内容:

Mongodb 笔记 (Part 1)

  1. Mac OSX下通过brew安装mongodb(brew install mongodb),如果需要升到最新版本则如下步骤,

    # 升级brew的版本库
    brew update
    
    # 查看outdated的库和应用
    brew outdated
    
    # 升级outdated的库和应用
    brew upgrade
    
    # 清理调过期的库和应用
    brew cleanup
    
  2. 安装完成后如需开机启动,则跟着brew info mongodb配置即可,
    ==> Caveats
    To reload mongodb after an upgrade:
        launchctl unload ~/Library/LaunchAgents/homebrew.mxcl.mongodb.plist
        launchctl load ~/Library/LaunchAgents/homebrew.mxcl.mongodb.plist
    Or, if you don't want/need launchctl, you can just run:
        mongod --config /usr/local/etc/mongod.conf
    ➜  ~  
    

    mongod默认的数据库路径为/data/db,所以sudo mkdir -p /data/db,然后需要将权限调回启动mongod的用户,sudo chown nonocast:wheel /data/db。

  3. mongod是服务程序,而mongo是mongod的shell,是client,这点需要明确。
  4. 热身,shell下打开mongo,默认use test数据库,切换到你自己use mydb,然后db.test.insert({name: "nonocast"})即完成了新建collection以及创建document 2个动作,然后通过db.test.drop()删除测试数据。
  5. 通过show collections可以查看当前的collection,通过db.createCollection(name)创建,通过具体collection drop删除,use会自动切换到新的数据库,而通过db.dropDatabase()删除当前所选中的数据库。
  6. 具体的database api可以见Database Methods — MongoDB Manual 2.6.4
  7. mongodb的2个核心概念,collection和document
  8. collection.find中可加入搜索条件,比如db.users.find( { age: { $gt: 18 } }, { name: 1, address: 1 } ).limit(5)
  9. CRUD,对应collection.insert(document), collection.update(criteria, document), collection.remove(criteria)
  10. mongodb admin UIs提供了很多通过web/app来管理mongodb的工具,眼花缭乱。最终在smog和mongo-express中选了mongo-express。

    npm install mongo-express -g后cd /usr/local/lib/node_modules/mongo-express,通过npm get config prefix获取全局安装路径,cp config.default.js config.js,基本不用修改,然后node app打开浏览器localhost:8081即可。

RFC 6455笔记

RFC 6455: http://tools.ietf.org/html/rfc6455

  • The WebSocket Protocol enables two-way communication between a client running untrusted code in a controlled environment to a remote host that has opted-in to communications from that code. The security model used for this is the origin-based security model(同源策略) commonly used by web browsers. The protocol consists of an opening handshake followed by basic message framing,layered over TCP. The goal of this technology is to provide a mechanism for browser-based applications that need two-way communication with servers.
  • WebSocket的版本历程,
       +--------+-----------------------------------------+----------+
       |Version |                Reference                |  Status  |
       | Number |                                         |          |
       +--------+-----------------------------------------+----------+
       | 0      + draft-ietf-hybi-thewebsocketprotocol-00 | Interim  |
       +--------+-----------------------------------------+----------+
       | 1      + draft-ietf-hybi-thewebsocketprotocol-01 | Interim  |
       +--------+-----------------------------------------+----------+
       | 2      + draft-ietf-hybi-thewebsocketprotocol-02 | Interim  |
       +--------+-----------------------------------------+----------+
       | 3      + draft-ietf-hybi-thewebsocketprotocol-03 | Interim  |
       +--------+-----------------------------------------+----------+
       | 4      + draft-ietf-hybi-thewebsocketprotocol-04 | Interim  |
       +--------+-----------------------------------------+----------+
       | 5      + draft-ietf-hybi-thewebsocketprotocol-05 | Interim  |
       +--------+-----------------------------------------+----------+
       | 6      + draft-ietf-hybi-thewebsocketprotocol-06 | Interim  |
       +--------+-----------------------------------------+----------+
       | 7      + draft-ietf-hybi-thewebsocketprotocol-07 | Interim  |
       +--------+-----------------------------------------+----------+
       | 8      + draft-ietf-hybi-thewebsocketprotocol-08 | Interim  |
       +--------+-----------------------------------------+----------+
       | 9      +                Reserved                 |          |
       +--------+-----------------------------------------+----------+
       | 10     +                Reserved                 |          |
       +--------+-----------------------------------------+----------+
       | 11     +                Reserved                 |          |
       +--------+-----------------------------------------+----------+
       | 12     +                Reserved                 |          |
       +--------+-----------------------------------------+----------+
       | 13     +                RFC 6455                 | Standard |
       +--------+-----------------------------------------+----------+
    

    如上表所见,RFC 6455已经是正式版本,也是整个草案的第十个版本,网上也有用人hybi09,hybi10来表示RFC 6455,知道一下就OK了。

  • 整个WebSocket协议分为2个阶段,先握手,握手成功后升级为WebSocket开始通信,原文描述: After a successful handshake, clients and servers transfer data back and forth in conceptual units referred to in ths specification as "message". On the wire, a message is composed of one or more frames.
  • A frame has an associated type. Each frame belonging to the same message contains the same type of data. Broadly speaking, there are types for texture data(UTF-8), binary data and control frames. This version of the protocol defines six frame types and leaves ten reserved for future use.
  • The handshake from the client looks as follows:
    GET /chat HTTP/1.1
    Host: server.example.com
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
    Origin: http://example.com
    Sec-WebSocket-Protocol: chat, superchat
    Sec-WebSocket-Version: 13
    

    其中Leading Line + Request Line符合HTTP[RFC2612],首先由client发起请求升级为WebSocket协议连接,Host区分网站(domain)这个不用解释了,而/chat则区分同站点中不同的websocket域,即同一站点内允许多个websocket server。Upgrade+Connection+Sec-WebSocket-Key则是向server申请提升。
    其中Sec-WebSocket-Key为base64编码,此key需要验证后续response中的Sec-WebSocket-Accept是否匹配。
    而Sec-WebSocket-Protocol则是应用协议,这个看程序了,协议本身不关心。

  • The handshake from the server looks as follows:
    HTTP/1.1 101 Switching Protocols
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
    Sec-WebSocket-Protocol: chat
    

    server回复就简单很多,如果提交上来又Upgrade+Connection+Sec-WebSocket-Key则将此Key+"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"然后计算此字符串的SHA-1通过base64返回给client。
    回复的Leading line如果同意提升则status code为101,其余都认为失败。一旦101后双方就可以通信了。

  • WebSocket是基于TCP的,仅依赖HTTP进行握手,升级后脱离HTTP协议,WebSocket协议允许和HTTP共用80端口,或者同时共用443。
  • WebSocket URI定义了2种scheme,如下,
    • ws-URI = "ws:" "//" host [ ":" port ] path [ "?" query ]
    • wss-URI = "wss:" "//" host [ ":" port ] path [ "?" query ]

    ws端口默认80,wss默认443。

Continue reading

Using SQLite in C

第一次用'母语'和SQLite打交道,真是又紧张又激动。对照SQLite权威指南发现网上除了官网本身的文档其他都多少有点出入,尽量看官方文档,你懂的。

先快速浏览一下C API,List Of SQLite Functions,正如文档所说,从开始的5个接口一直到现在的200多个接口,不过对比SQLServer, Mysql还是OK的。其中最为核心的概念和方法差不多是2+6,

2个核心对象是:

  • The database connection object: sqlite3
  • The prepared statement object: sqlite3_stmt

6个最常用的方法是:

  • sqlite3_open()
  • sqlite3_prepare()
  • sqlite3_step()
  • sqlite3_column()
  • sqlite3_finalize()
  • sqlite3_close()

官网上很明确的指出sqlite3_exec和sqlite3_get_table都是对prepare/step的封装,务必理解prepare/step的运作方式,但在实际情况中,个人建议除了create以外都用prepare/step来解决,后面会说到原因。

还是从hello world开始,

Continue reading

Time in shell

.NET中我们通过Stopwatch来测试一个功能所耗费的时间,在Linux下当然也可以通过clock来得到begin和end,但是借助shell更加简便。

➜  ~  time sleep 3
sleep 3  0.00s user 0.00s system 0% cpu 3.004 total
➜  ~  

一开始我还没看懂这句,解释一下,
[目标命令语句] [user时间] [system时间] [cpu占用率] [总时间]

user/system我个人理解为用户和内核,比如IO操作占用system远多过user,我们最关心的是整体时间也就是3.004,非常精确的数值。

参考内容:

Say hello to Caliburn.Micro

在实践过程中你越多WPF你越会发现ViewModel是必不可少的,因为Model和View的匹配度事实上并不高,在写了N个ViewModel后来看看社区的框架学习一下,不过不看不知道,.NET Mvvm社区那个乱啊...有点失望。Anyway,有以下选择:

虽然Prism是官方选定的Mvvm,但问题是其文档冗长无比,好评度并不高,而MvvmLight则文档乏善可陈,最后根据devdigital周永恒的推荐下决定从CM开始。

来看Caliburn.Micro的hello world,
Continue reading

Using yo (Part 2)

Part 1来看怎么extend generator。

首先切换到coffee-script,由于yo只认js,所以index.js中做过过渡,

require('coffee-script/register'); // cs1.7+
require('coffee-script');
module.exports = require('./index.coffee');

注: cs1.6 require('coffee-script'); cs1.7 require('coffee-script/register');

用coffee当然需要npm install coffee-script --save,这样才能require。然后index.coffee如下,

yeoman = require 'yeoman-generator'

class HelloGenerator extends yeoman.generators.Base
  constructor: (arg, options, config) ->
    yeoman.generators.Base.apply this, arguments
    this.config.save()

  hello: ->
    console.log 'hello coffee'

module.exports = HelloGenerator

然后yo试试。

Continue reading