Thursday, January 7, 2010

golang中的迭代

python中的这种功能:

for key, value in a.items(): print key, value

go language也有这种功能:

func main() {
    var infomation string = "中国比美国好多了.";
    fmt.Println( infomation );
    //是unicode吗? 答案:否
    fmt.Println( len( infomation ) );
    fmt.Printf("%c\n", infomation[0]);
    for index, value := range infomation {
        //%c与C中的%c不同      the character represented by the corresponding Unicode code point
        fmt.Printf("%d:%c ", index, value);
    }
}
输出結果:
中国比美国好多了.
25
ä
0:中 3:国 6:比 9:美 12:国 15:好 18:多 21:了 24:.

range一个string时, 为unicode code point, 而不是byte

golang中的字符串

golang的String type与python的basestring实例差不多.

immutable

python里str的情况:
In [3]: name = str("abcde")
In [4]: name[1]
Out[4]: 'b'
In [5]: name[1] = "3"
TypeError: 'str' object does not support item assignment

python里unicode的情况:
In [6]: name = unicode("abcde")
In [7]: name[2]
Out[7]: u'c'
In [8]: name[2] = u'f'
TypeError: 'unicode' object does not support item assignment

golang中的string类型也是immutable的:

func main() {

    var name string = "abcd";
    fmt.Printf("%c\n", name[2]);
    //这种修改将会产出错
    name[1] = 'c';
    //只能得到string变量的开始地址.
    fmt.Printf("%p\n", &name);
    //下面会报错, 因为不能求元素的地址!
    fmt.Prinft("%p\n", &name[2]);

}

string literals

在字符串上, golang使用三种符号:
1. 单引号: 与C一样, 表示是byte,
2. 双引号: 与C一样, 表示N种byte,  只是golang中不可以修改和求元素的地址.
3. 反引号: 不解释字符串的转义符.

python中也有这三种用法, 只是使用的表达方式:
1. 单(双)引号: 表示N种chr实例的集合
2. u开头的unicode string literals, 还没有发现golang有unicode string literals
3. r开头的string literals:

In [10]: print   r'a\nb'
a\nb

unicode问题

双引号得到的是不可修改的byte集. 不是unicode类型!

下面做一个测试, 先得到一个汉字的外码和unicode码:
In [14]: u'中'
Out[14]: u'\xe4\xb8\xad'
In [15]: unicode('中', "utf-8")
Out[15]: u'\u4e2d'

再看golang的代码:

func main() {
    var infomation string = "\u4e2d"; //使用unicode的标志法, 也无法改变string就是byte集的现实!
    fmt.Println( infomation );
    //是unicode吗? 答案:否
    fmt.Println( len( infomation ) );
    fmt.Printf("%x", infomation);
}

输出的結果是:

3
e4b8ad

golang中怎么样python一样, 有unicode string literals呢? 答案: 没有!

只有使用函数得到。


golang中的slice

slice 数据类型大概原理是这样的:

type Slice struct {
  base *elem_type;
  len int;
  cap int;
}

最容易和数组乱的就是下面的这样声明:
  var a []int;

空长度表示变量是一个slice type, 不是空数组。

下面的使用方式:
var slice = []int{ 1,2,3,4,5 }; //这是产生一个数组, 然后产生一个slice
* 在这种背后创建了数组的情况, golang提供了reslice和cap函数功能

与下面的是不同的:
var ar = [...]int{ 1,2,3,4,5 };

golang中的slice与python中的list的slice是不同的.
1. [:8] 没有隐含的开始方式, 也没有隐含的结束方式
2. [1:999999999] 超出不等于到最后, 报错!
3. 没有负数的end, 报错.

func main() {
    //创建一个slice, 它是引用[8]int的
    ar := []int {0, 1, 2, 3, 4, 5, 6, 7};
    //slice类型支持reslice, 調整它的引用情况
    ar = ar[2:4];
    fmt.Printf("length: %d\n", len(ar));
    fmt.Println(ar[0]);
   
    //怎么重新引用[8]int的完整长度呢? 答案是否定的
    //提供了cap()函数
    ar = ar[0:cap(ar)];
    fmt.Printf("length: %d\n", len(ar));
    fmt.Println(ar[0]);
}

输出結果是:
length: 2
2
length: 6
2

reslice无法修改slice的起始地址. 只能修改结束地址. capacity的长度会保存不变(除非引用了其它数组)

一步产生数组和slice变量:

var a = &[100]int{};

但是这样是不行的:

var a = &[100]int;

还可以使用make()函数:
a := make([]int, 100);

make([]int) 是等于[]int , 为一个slice对象

new([]int) 返回 *[]int , 为指向slice的指针变量.

Wednesday, January 6, 2010

golang中的指针数组

在golang的文档里没有看到怎么声明指针数组的例子(不知道是不是自己看漏了)

文档里本人只看到“指向数组的指针”的声明。如:
  var p2array *[3]int;

不知道什么时候突然一个想法就出来了:
  var pointers [3]*int;
这就是指针数组的声明。和文档里说的指向数组的指针的声明是不同的。

试了一下, 还真的可以的, 牛B!!

import "fmt"
func main() {

    var ar [3]*int;
    //这是真的吗?
    fmt.Println(len(ar));
   
    value := new(int);
    *value = 3;
    //存放指针
    ar[0] = value;
    fmt.Println(*(ar[0]));

}


Tuesday, January 5, 2010

amule下载完的文件名乱码问题

最近使用amule的次数比较好, 发现amule像一个金矿, 里面太奶奶的多好货了.

当然, 也不是白取的, 从我notebook上upload的数据都有33G多了. 下载点也是正常的.

不过, 奶奶的, 今天在Incoming里找文件, 无法忍受amule下载的文件名是乱码一事~ 决定清理!

In [76]: f = os.listdir('.')

In [77]: for i in range(len(f)):
                   if f[i].startswith("LINUX"):
                           print i
Out[77]: 8
找出自己要试验的一条文件名

乱码, 一般都是gbk编码吧, 于是:
In [81]: print f[8].decode("gbk")
-------> print(f[8].decode("gbk"))
LINUX莽鲁禄莽禄聼莽庐隆莽聬聠忙聤聙忙聹炉忙聣聥氓聠聦茂录聢莽卢卢2莽聣聢茂录聣.pdf


顶~~~~~~ 屁都不是. 又试了几种编码都不行~~~~ 试多了几次, 发现一个现象:

In [87]: f[8].decode("utf-8")
Out[87]: u'LINUX\xe7\xb3\xbb\xe7\xbb\x9f\xe7\xae\xa1\xe7\x90\x86\xe6\x8a\x80\xe6\x9c\xaf\xe6\x89\x8b\xe5\x86\x8c\xef\xbc\x88\xe7\xac\xac2\xe7\x89\x88\xef\xbc\x89.pdf'

In [88]: print "\xe7\xb3\xbb"
-------> print("\xe7\xb3\xbb")


* 从上面取出的一段外码, 是可以正确显示的. 看来amule是把unicode的文件名直接给str()成raw string串了. 乱码就是这样产生的:

In [108]: c = u'梁'

In [109]: c
Out[109]: u'\xe6\xa2\x81'

In [110]: str(c)
Out[110]: '\xc3\xa6\xc2\xa2\xc2\x81'

In [111]: print str(c)
--------> print(str(c))
æ¢

现在的问题是怎么把上面一串为unicode的外码整成raw string呢?

现在的目标是把u'\xe7'转成'\xe7', 如下方法:
In [153]: chr(ord(u'\xe7'))
Out[153]: '\xe7'


OK, 妈的。 一个for处理完你~~~ 狗日的乱码

#!/usr/bin/env python
# coding: utf-8
import os

DIR="/home/jessinio/.aMule/Incoming"

for f in os.listdir( DIR ):
    print f
    retval = []
    for i in f.decode("utf-8"):
        # 文件名本身没有乱码的情况时, 会是unicode, 这时ord的值为unicode的内码, 超过256
        if ord(i) > 256:
            retval.append(i.encode("utf-8"))
        else:
            retval.append(chr(ord(i)))
    print ''.join(retval)
    os.rename( os.path.join(DIR, f), os.path.join( DIR, ''.join(retval) ) )


golang中的指针

总结一下golang中的指针与C语言的指针的用法.

总体一致:
C的代码:
    int *number;
    number = (int *) malloc(sizeof(int));
    *number = 3;
    printf("%d\n", *number);

golang的代码:
    var pointer *int;
    pointer = new(int);
    *pointer = 3;
    fmt.Println(*pointer);

多重指针情况:
C的代码:
    int **outer;
    int *inter;
    inter = (int *) malloc(sizeof(int));

    *inter = 3;
    outer = &inter;
    //地址一样
    printf("%p\n", inter);
    printf("%p\n", *outer);
    //值一样
    printf("%d\n", *inter);
    printf("%d\n", **outer);

golang的代码:
    var outer **int;
    var inter *int;
    inter = new(int);
    *inter = 3;
    outer = &inter;
    //地址一样
    fmt.Println(inter);
    fmt.Println(*outer);
    //值一样
    fmt.Println(*inter);
    fmt.Println(**outer);

C语言的下面这种方式在golang里实现:
    int **outer;
    int *inter;
    inter = (int *) malloc(sizeof(int));
    outer = (int **) malloc(sizeof(int));
   
    *inter = 3;
    *outer = inter;
    //地址一样
    printf("%p\n", inter);
    printf("%p\n", *outer);
    //值一样
    printf("%d\n", *inter);
    printf("%d\n", **outer);

在golang中:
    var inter *int;
    var outer **int;
    inter = new(int);
    *inter = 3;
    outer = new(*int);
    *outer = inter;
    //地址一样
    fmt.Println(inter);
    fmt.Println(*outer);
    //值一样
    fmt.Println(*inter);
    fmt.Println(**outer);

上面都是在玩指针, 下面看看基本的数据结构

基本的数据结构有: 数组与结构体 (map和树之类的不在討論范围)

golang中的数组与C中的数组有很大的差别

golang中的数组是这样说的: Arrays are values, not implicit pointers as in C.

0. 数组做参数时, 需要被检查长度.
1. 变量名不等于数组开始指针!
2. 不支持C中的*(ar + sizeof(int))方式的指针移动. 需要使用到unsafe包
3. 如果p2array为指向数组的指针, *p2array不等于p2array[0]

例子0 数组做参数时, 需要被检查长度.

func use_array( args [4]int ){
    args[1] = 100;
}

func main() {
    var args = [5]int{1, 2, 3, 4, 5};
    use_array(args);
    fmt.Println(args);
}

编译出错: cannot use args (type [5]int) as type [4]int in function argument, 需要有长度上的检查

例子1 变量名不等于数组开始指针!

func use_array( args [4]int ){
    args[1] = 100;
}

func main() {
    var args = [5]int{1, 2, 3, 4, 5};
    use_array(args);
    fmt.Println(args);
}

输出結果是 [1 2 3 4], 没有保存結果, 数组名的用法与C的不一样. 在golang里是这样的:

// 又长度检查, 也为地址传参
func use_array( args *[4]int ){
    args[1] = 100;  //但是使用还是和C一致, 不需要别加"*"操作符
}
            
func main() {        
    var args = [4]int{1, 2, 3, 4};
    use_array(&args); //数组名已经不是表示地址了, 需要使用"&"得到地址
    fmt.Println(args);
}

例子2 如果p2array为指向数组的指针, *p2array不等于p2array[0]
对比一下C和golang在这方面的差别:
void main(int argc, char *argv[]){
    int *p2array;
    p2array = (int *) malloc(sizeof(int) * 3);
    //等于p2array[0]
    *p2array = 0;
    printf("%d\n", *p2array + 1);
}
* 输出为1

func main() {
    var p2array *[3]int ;
    p2array = new([3]int);
    fmt.Printf("%x\n", *p2array + 1); //不管p2array是指针变量还是数组变量, 都只能使用"[]"方式使用
}
* 报错.

golang中的结构体也与C中的有差别


下面的方式是相当一致的:
C版本的:
    typedef struct
    {  
        int x;
        int y;
    } Point;

    Point p;
    p.x = 10;
    p.y = 20;
   
    //开始地址
    printf("%p\n", &p);
    //某元素地址
    printf("%p\n", &(p.x));

golang版本的:
    type Point struct{
        x int;
        y int;
    };
   
    var p Point;
    p.x = 10;
    p.y = 20;
    fmt.Printf("%p\n", &p);
    fmt.Printf("%p\n", &(p.x));

使用allocate的方式:
C代码:
    typedef struct
    {  
        int x;
        int y;
    } Point;

    Point *p;
    p = (Point *) malloc(sizeof(Point));
    p->x = 10;
    p->y = 20;
   
    //开始地址
    printf("%p\n", p); //地址
    //某元素地址
    printf("%p\n", &(p->x));

golang代码:
    type Point struct{
        x int;
        y int;
    };
   
    var p *Point;
    p = new(Point);
    p.x = 10;
    p.y = 20;
    fmt.Printf("%p\n", p); //地址
    fmt.Printf("%p\n", &(p.x));

也可以说是一样的, 只不过在使用结构中的元素时没有了"->"操作符:
There is no -> notation for structure pointers. Go provides the indirection for you.  

结构体的地址传参与数组的方式一样, 当然, 和C的风格也是一模一样的. 如下例子:

C代码:
#include <stdio.h>
#include <stdlib.h>
typedef struct
    {
        int x;
        int y;
    } Point;
    
void use_struct(Point *arg){
    arg->x = 100;
}

void main(int argc, char *argv[]){
    
    Point *p;
    p = (Point *) malloc(sizeof(Point));
    p->x = 10;
    p->y = 20;
    
    use_struct(p);
    printf("%d\n", p->x);

}

golang代码:
import "fmt"

type Point struct{
    x int;
    y int;
};

func use_sturct( p *Point ){
    p.x = 100;
}

func main() {

    var p *Point;
    p = new(Point);
    p.x = 10;
    p.y = 20;
    use_sturct(p);
    fmt.Printf("%d\n", p.x);
}

总的来说......

在传参方面, 大体上看与C的相同:

  f(ar);    // passes a copy of ar

  fp(&ar);  // passes a pointer to ar
* 只是变量名是不是表示首个地址 有区别


"&" 与C语言一样是得到变量的指针. 与C有点不同, 取golang中指针指针的内容的值是不需要使用"*"操作符的, 但是指针的指针(或者继续多层时)需要显式使用"*"符号.
在http://golang.org/doc/go_spec.html#Selectors 一节中有描述。

* 三层以上的指针使用是比较少的. 两层还是常见, 如main函数的参数char * argv[]



Monday, January 4, 2010

man命令出现 ESC[ 控制符

安装gentoo时, 出现使用man查看手册时出现一堆 ESC[ 之类的字符。
这些字符是consolse下的颜色控制。

了解了一下。 原来man命令也是调用外部程序来显示的。三个选项:
-P, -B, -H

然后对比一下ubuntu下的man和gentoo下的man, 发现不同的man手册这方面已经变化。

下面是gentoo的(man version 1.6f)
       -P  pager
              Specify which pager to use.  This option  overrides  the  MANPAGER  environment  variable,
              which in turn overrides the PAGER variable.  By default, man uses /usr/bin/less -is.

下面是ubuntu9.10的(man 2.5.6)
       -P pager, --pager=pager
              Specify which output pager to use.  By default, man uses pager -s.  This option overrides the $MAN‐
              PAGER environment variable, which in turn overrides the $PAGER environment  variable.   It  is  not
              used in conjunction with -f or -k.

调用的程序已经不同.

在不安装pager程序下, 可以使用less程序的-R参数

       -R or --RAW-CONTROL-CHARS
              Like  -r, but only ANSI "color" escape sequences are output in "raw" form.  Unlike -r, the
              screen appearance is maintained correctly in most cases.  ANSI  "color"  escape  sequences
              are sequences of the form:

所以, 让gentoo下的man不出现一堆 ESC[ , 可以:
export PAGER='less -R'