iovxw

Golang类型switch

语法强迫症

在群里讨论到了这个问题

然后下面这是官方给出的例子

var t interface{}
t = functionOfSomeType()
switch t := t.(type) {
default:
    fmt.Printf("unexpected type %T", t)       // %T prints whatever type t has
case bool:
    fmt.Printf("boolean %t\n", t)             // t has type bool
case int:
    fmt.Printf("integer %d\n", t)             // t has type int
case *bool:
    fmt.Printf("pointer to boolean %t\n", *t) // t has type *bool
case *int:
    fmt.Printf("pointer to integer %d\n", *t) // t has type *int
}

里面有几点要注意一下

switch t := t.(type)

switch的其实是t.(type)而不是被创建的t

然后t := t.(type)创建的是类型为t.(type),值为t的值的一个变量

里面所使用的t都是switch里新建的那个t


等于下面这个例子

var t interface{}
t = functionOfSomeType()
switch t.(type) {
default:
    fmt.Printf("unexpected type %T", t)       // %T prints whatever type t has
case bool:
    t := t.(bool)
    fmt.Printf("boolean %t\n", t)             // t has type bool
case int:
    t := t.(int)
    fmt.Printf("integer %d\n", t)             // t has type int
case *bool:
    t := t.(*bool)
    fmt.Printf("pointer to boolean %t\n", *t) // t has type *bool
case *int:
    t := t.(*int)
    fmt.Printf("pointer to integer %d\n", *t) // t has type *int
}

更新了下模板

瞬间高大上

除了50行的custom.css和几行html修改之外全部都是直接找的模板哇咔咔

虽然上上上次说要重新写一个静态博客生成工具,而且Golang的模板工具和页面模板已经写完了。但是最近又开了个坑所以就……

无限延期吧……

LevelDB储存过程解析

写的乱糟糟的

本文是研究LevelDB结构之后为了加深印象写的,然后主要是写存储过程的细节(其实本来像画个gif来实现的,但是太麻烦了……)。细节部分都是靠各种资料总结的,然后推荐先看一下文章底部的资料,因为有些重复部分没写

如有理解错误,还请指出


首先收到一个添加key的请求,先直接写入log文件(追加写入)

然后插入到内存的储存区(内存储存区内按照key的顺序排列),等到内存储存的数据达到一定大小后(1M),将内存内的数据写入level为0的sst文件内,然后删除log(这里说一下需要注意的是level0内的数据都是直接从内存写入的,所以不同sst文件的key可能会有重复,和其他level不同,其他level在合并的时候都会去掉重复key,不过level0不经过合并这个步骤(当然要是每次从内存写入的时候都更新一下也行,但是io消耗太大,不如在合并到level1的时候进行操作)。所以说level0和其他level相比,更像一个缓存数据用的)

等到level0级别的sst文件达到一定数量后,挑选其中一个sst文件合并到level1(如果没有level1那么就生成level1,其他level也是这么来的。然后因为level0会有重复key(上面也说过原因),所以合并到level1的时候会先去掉和被选中的sst文件内重复的key再合并(所以可能会涉及到level0级别的多个sst文件更新))

合并的时候会检查level0中的key是否和level1中的key有重合,如果有重合那就读取重合的文件和level0中被挑选的sst文件进行更新key,然后排序key之后再按照2M一个sst文件写入level1(这里就可以看出key按照顺序排列的好处了,因为挨着的key基本都在一个文件里,从level0里选择sst文件的key是挨着的,level1的也是,更新的话只需要更新1~2个文件,能减少需要读取的sst文件个数。比如level0抽取的sst文件key是A1~C3的,和level1里面A1~C5的sst刚好能重合,就只需要读取一个文件进行合并了。如果是按照插入顺序之类的乱序,可能会从N个文件里找到重复的key,合并需要读取的文件也就会更多了)

等到level1的文件数据达到10M时(每个级别最大数据量为10^level,level1为10M,level2就是100M),就选择其中一个sst文件合并到leve2。合并方法也是找到重复的key更新,排序,然后生成sst。不过这一层的sst单个文件不再是2M,而是更大一些,每增加一层sst文件最大限制都会扩大。这样设计是为了一层满了之后不至于逐层更新。

剩下的level层也是像上面那样进行更新,所以level最大的一层,数据也是最旧的

删除操作和更新操作基本也都是直接插入数据,只不过删除操作插入的是删除标记,更新操作是直接重新插入一遍数据(在level合并的时候会进行处理更新)

在进行读取key的时候,会先从内存查找是否有这个key,然后再到level0查找,如果还是没有就会到更高层level挨个查找,因为越高层数据越旧,没有被更新到的可能也就越大(比如一个储存在level3的key被在level2标记了删除,但是还没更新到。那么当查找这个key的时候就会优先找到在level2的删除标记(当然level3的key也会在多次合并操作之后被删除掉))

本文章配合以下资料阅读更佳:

http://blog.nosqlfan.com/html/2882.html

http://www.cnblogs.com/haippy/archive/2011/12/04/2276064.html

Golang 模板工具

生成器

就是上一篇文章里说的那个,写完之后发现挺奇葩的

项目地址:https://github.com/Bluek404/GoHTML

介绍什么的直接扔README了:


GoHTML

 ██████╗         ██╗  ██╗████████╗███╗   ███╗██╗
██╔════╝  █████╗ ██║  ██║╚══██╔══╝████╗ ████║██║
██║  ███╗██╔══██╗███████║   ██║   ██╔████╔██║██║
██║   ██║██║  ██║██╔══██║   ██║   ██║╚██╔╝██║██║
╚██████╔╝╚█████╔╝██║  ██║   ██║   ██║ ╚═╝ ██║███████╗
 ╚═════╝  ╚════╝ ╚═╝  ╚═╝   ╚═╝   ╚═╝     ╚═╝╚══════╝

Golang HTML模板,非正式项目

基本就是写着玩的

可以将Golang和HTML写在一起,然后用本工具转换成Golang文件

基本功能就是将<a>转换成buffer.WriteString("<a>")

例子

转换前:

package tpl

import (
	"fmt"
	"bytes"
)

func Index() string {
	_buffer := new(bytes.Buffer)

	<a>Text</a>

	for i:=0; i<10; i++ {
		<a>{​{string(i)}}</a>
	}

	var t string = "2"
	fmt.Println(t)

	print:=func() {
		<a>text</a>
	}
	print()

	test1(_buffer)
	test2(_buffer, t)

	return _buffer.String()
}

func test1(_buffer *bytes.Buffer) {
	<a>test1</a>
}

func test2(_buffer *bytes.Buffer, t string) {
	<a>test{​{t}}</a>
}

转换后:

package tpl

import (
	"fmt"
	"bytes"
)

func Index() string {
	_buffer := new(bytes.Buffer)

	_buffer.WriteString("<a>Text</a>")

	for i:=0; i<10; i++ {
		_buffer.WriteString("<a>")
		_buffer.WriteString(string(i))
		_buffer.WriteString("</a>")
	}

	var t string = "2"
	fmt.Println(t)

	print:=func() {
		_buffer.WriteString("<a>text</a>")
	}
	print()

	test1(_buffer)
	test2(_buffer,t)

	return _buffer.String()
}

func test1(_buffer *bytes.Buffer) {
	_buffer.WriteString("<a>test1</a>")
}

func test2(_buffer *bytes.Buffer, t string) {
	_buffer.WriteString("<a>test")
	_buffer.WriteString(t)
	_buffer.WriteString("</a>")
}

然后就可以直接调用里面的函数作为http.HandleFunc

使用帮助

$ go run GoHTML.go

 ██████╗         ██╗  ██╗████████╗███╗   ███╗██╗
██╔════╝  █████╗ ██║  ██║╚══██╔══╝████╗ ████║██║
██║  ███╗██╔══██╗███████║   ██║   ██╔████╔██║██║
██║   ██║██║  ██║██╔══██║   ██║   ██║╚██╔╝██║██║
╚██████╔╝╚█████╔╝██║  ██║   ██║   ██║ ╚═╝ ██║███████╗
 ╚═════╝  ╚════╝ ╚═╝  ╚═╝   ╚═╝   ╚═╝     ╚═╝╚══════╝
=====================================================
GoHTML使用帮助:
===============

命令结构:
  命令 [参数] <模板文件夹路径>

参数:
  -dl <字符串>     | 默认:{{      | 左分隔符样式
  -dr <字符串>     | 默认:}}      | 右分隔符样式
  -suffix <字符串> | 默认:gohtml  | GoHTML模板文件后缀
  -buffer <字符串> | 默认:_buffer | 缓冲器变量名称

举例:
  $ gohtml -dl <{ -dr }> -suffix temp -buffer buf /home/bluek404/gocode/web/view
   | 则会将
   | /home/bluek404/gocode/web/view
   | 里面所有temp为后缀的文件转换为go文件后放到同一文件夹内
   | 将缓冲器变量名称设为“buf”
   | 并设置左分隔符为“<{” ,右分割符为“}>”

备注:
  方括号[]为选填项目,尖括号<>为必填项目

源码规范

作为http.HandleFunc的函数,必须返回值只有一个string(因为多了就不符合http.HandleFunc的要求了)

然后里面必须创建一个类型为*bytes.Buffer的变量,变量名称需要和设置的一样(默认是_buffer)。这个缓冲器是用于存放要输出的HTML代码的

然后作为http.HandleFunc的函数的返回值需要是_buffer.String(),如果你自定义了缓冲器变量名称,需要相应的改变

负责处理部分html的函数,推荐写成上面例子里的样式(接收一个缓冲器变量),就像:

func test1(_buffer *bytes.Buffer) {
    <a>test1</a>
}

因为会转换成:

func test1(_buffer *bytes.Buffer) {
    _buffer.WriteString("<a>test1</a>")
}

这个样子

当然你要是写成函数里新建一个缓冲器变量然后再return也是没问题的

不过那样就需要在使用函数的地方再加一个输出了(相当麻烦)

所以就乖乖按照标准写吧

然后还有一点要注意

就是分隔符输出变量那里,比如{​{t}}

这里的分隔符只有在HTML中才会被转换,就像<a>{​{t}}</a>

写在别的地方是不会转换的,比如:

<a>
if i==0 {
    {​{t1}}
}else{
    {​{t2}}
}
</a>

必须写成

if i==0 {
    <a>{​{t1}}</a>
}else{
    <a>{​{t2}}</a>
}

这样才可以

自动转换

每次更新完模板后都要手动执行一次转换工具一定是超麻烦的

所以需要自动的工具

这里推荐UnknwonBRA(名字好像有点奇怪?),当然其他相似功能的工具也是可以的(如果有更好的还拜托推荐一下)

具体使用方法这里就不说了,自己去看吧

下载

Gobuild Download

在写一个新的静态博客生成工具

轮子、轮子、轮

目标是“完全没有可定制性”

模板已经写好了

但是后端基本没写

而且因为Golang本身的template包实在不好用

于是准备重写一个(又是大坑)

然后……

估计就没有然后了……

换了一个高亮插件

还是因为懒……

这个高亮脚本就叫做highlightjs

因为主题比较多

所以就直接换成这个了

支持92种语言和49种高亮主题

官网:
https://highlightjs.org

主题列表&预览: https://highlightjs.org/static/test.html

package main

import (
	"fmt"
	"math/rand"
	"sync/atomic"
	"time"
)

type readOp struct {
	key  int
	resp chan int
}
type writeOp struct {
	key  int
	val  int
	resp chan bool
}

func main() {

	var ops int64

	reads := make(chan *readOp)
	writes := make(chan *writeOp)

	go func() {
		var state = make(map[int]int)
		for {
			select {
			case read := <-reads:
				read.resp <- state[read.key]
			case write := <-writes:
				state[write.key] = write.val
				write.resp <- true
			}
		}
	}()

	for r := 0; r < 100; r++ {
		go func() {
			for {
				read := &readOp{
					key:  rand.Intn(5),
					resp: make(chan int)}
				reads <- read
				<-read.resp
				atomic.AddInt64(&ops, 1)
			}
		}()
	}

	for w := 0; w < 10; w++ {
		go func() {
			for {
				write := &writeOp{
					key:  rand.Intn(5),
					val:  rand.Intn(100),
					resp: make(chan bool)}
				writes <- write
				<-write.resp
				atomic.AddInt64(&ops, 1)
			}
		}()
	}

	time.Sleep(time.Second)

	opsFinal := atomic.LoadInt64(&ops)
	fmt.Println("ops:", opsFinal)
}

给博客添加了代码高亮

Google Code Prettify

使用的是Google Code Prettify

因为这个js是google code用的,所以各种语言支持比较全面(当然主要是因为Golang才用的)

直接用的默认css

所以和博客主题不是很搭

准备有时间自己修改一下(目测这几个月内是不行了)

来一段测试一下:

package main

import (
	"fmt"
	"math/rand"
	"sync/atomic"
	"time"
)

type readOp struct {
	key  int
	resp chan int
}
type writeOp struct {
	key  int
	val  int
	resp chan bool
}

func main() {

	var ops int64

	reads := make(chan *readOp)
	writes := make(chan *writeOp)

	go func() {
		var state = make(map[int]int)
		for {
			select {
			case read := <-reads:
				read.resp <- state[read.key]
			case write := <-writes:
				state[write.key] = write.val
				write.resp <- true
			}
		}
	}()

	for r := 0; r < 100; r++ {
		go func() {
			for {
				read := &readOp{
					key:  rand.Intn(5),
					resp: make(chan int)}
				reads <- read
				<-read.resp
				atomic.AddInt64(&ops, 1)
			}
		}()
	}

	for w := 0; w < 10; w++ {
		go func() {
			for {
				write := &writeOp{
					key:  rand.Intn(5),
					val:  rand.Intn(100),
					resp: make(chan bool)}
				writes <- write
				<-write.resp
				atomic.AddInt64(&ops, 1)
			}
		}()
	}

	time.Sleep(time.Second)

	opsFinal := atomic.LoadInt64(&ops)
	fmt.Println("ops:", opsFinal)
}

上面这段源码来自于:

Go by Example 中文:Go 状态协程

Coding活动送的月饼收到

下午茶的东西全了

上面还附带一个开箱工具

外加一包铁观音

顺便在博客css里面加上了一段

.container img {
	max-width: 100%;
}

这样图片就自动缩放了

Twister 去中心化的 Twitter

FREEDOM!!

在36氪看见的文章

http://www.36kr.com/p/214845.html

于是就下载使用了一下

发现Arch的aur源里已经可以安装了

yaourt -S twister-core-git twister-html-git

然后配置一下

~/.twister/twister.conf

里面填入

rpcuser=user
rpcpassword=pwd
rpcallowip=127.0.0.1

上面的用户名和密码改成你自定义的就行了

这个用户名和密码只不过是用来识别本地管理员身份的,不是twister帐号

然后移动twister-html到~/.twister/html(twister-html的位置我忘了,搜索下吧)

su切换到root运行systemctl start twister开启服务

切换到普通用户运行twisterd开启主程序

打开网页http://127.0.0.1:28332/index.html输入你上面的用户名密码然后等待区块同步完成修改个人信息即可

官网:http://twister.net.co

参考信息:http://wiki.twister.net.co/w/using:howto:compiling_twister_on_ubuntu_12.04

近期的计划

懒啊………

又好久没写博客了

这次不是因为太忙

纯粹是懒

果然天一热就什么也不想干啊……

因为懒,所以也就有了一大堆代办事项

现在列出来备忘一下

  1. 学好js和css,然后修改一下博客的图片显示缩放等等
  2. 把上次写的那个梯子的坑填完,做一个网页管理系统和代理服务器群组的自动配置
  3. 填好2个Minecraft服务器的坑
  4. 攒钱租服务器
  5. 修改一下这个博客的生成器hugo,加强一下markdown解析什么的
  6. 攒钱给域名续费&&攒钱买游戏

一直想wine星际2,结果就是不成功,一直卡在检查更新中

看了一下应该是wine网络问题,如果始终不行的话还是去Steam买《Planetary Annihilation》吧,不过49刀太贵了(不知有没有土豪愿意送我 :D)

估计得慢慢等打折,上次打折后仅需5刀结果错过了,悲伤啊悲伤

感觉好懒……