2008年12月27日星期六
2008年12月24日星期三
perl thread tutorial
http://www.mathematik.uni-ulm.de/help/perl5/doc/perlthrtut.html
perldoc perlthrtut
1:创建线程
use threads;
my $thr = threads->new(\&sub1);
sub sub1{
print "In the threads";
}
也可以通过creat创建线程并为线程传递参数
new=create
my $thr = threads->create(\sub1,@paramlist);
2:等待线程结束
use threads;
my ($thr) = threads->new(\sub1);
my @return = $thr->join();
sub sub1{
return ('FiFty',1,2);
}
注意在这个例子中,sub1返回的是一个list,所以我们需要在定义线程时候使用my ($thr),这是给$thr一个list的上下文
3:忽略一个线程
join做三件事:等待线程推出,清理线程以及返回线程返回值。
如果你对线程没啥兴趣,可以使用detach不管它,perl会自动收拾这个进程
use threads
my $thr = threads->create(\&sub1);
$thr->detach();
sleep(15);
sub sub1{
my $a=0;
while(1){
$a++;
print "\$a is $a\n";
sleep 1;
}
}
sleep在这里的作用是使主进程多运行一些时间,否则主程序推出则线程也会退出
我们也可以在sub里面退出线程
sub sub1{
threads->detach();
}
4:数据共享
use threads;
use threads::shared;
my $foo:shared = 1;
my $bar = 1;
my $thr = threads->create(sub{$foo++;$bar++}->join();
print $foo,"\n"; #2
print $bar,"\n"; #1
使用hash作为共享数据要注意的是
my $foo:shared;
my $bar;
my %foo;
$foo->{bar} = \$bar #错误,必须使用共享数据的引用
5:使用数据共享带来的问题
考虑这样一个程序
use threads;
use threads::shared;
my $a :shared = 1;
my $thr1 = threads->create(\&sub1);
my $thr2 = threads->create(\&sub2);
$thr1->join;
$thr2->join;
print("$a\n");
sub sub1 { my $foo = $a; $a = $foo + 1; }
sub sub2 { my $bar = $a; $a = $bar + 1; }
这时候a的值是多少呢?sub1和sub2都对变亮a进行了修改,所以a的值是不确定的,可能是2也可能是3(我试了n次都是3)
6:同步和控制
访问控制:lock()
2008年12月23日星期二
UTF8与perl中的宽字符
首先澄清几个概念:
1. Perl中的字符串有两种存储方式:字节方式,宽字符方式(wide character)。
2. 宽字符方式每个字符占16位,是个0-65535的整数。
3. 宽字符的字符串不能被输出,也不能用作base64这样基于字节的字符串处理。
4. 为什么宽字符是16位?因为16位能完整地表示Unicode的所有字符。
你得到的 \x{6d4b}\x{8bd5}\x{4eba}\x{5458} 就是“测试人员”的宽字符形式。
5. 宽字符转换成字节要用 utf8::encode($str),反向转换用 utf8::decode($str)。
注意用这两个函数时不需要use utf8也不能use utf8,use utf8有别的意思,会产生重大影响!
6. \x{6d4b}\x{8bd5}\x{4eba}\x{5458}用 utf8::encode处理完后结果是
\xe6\xb5\x8b\xe8\xaf\x95\xe4\xba\xba\xe5\x91\x98
这才是应该传给 base64的数据。
2008年12月22日星期一
毛建军和老北京
不过我倒是看着kobe毛建军的外号成长起来的
zz一个
毛建军是NBA超级巨星科比·布莱恩特的众多绰号之一,科比的绰号如小飞侠、大婶、毛八一等,毛建军是从毛八一发展而来。
在2006年1月23日对阵猛龙队的一场NBA常规赛中,科比在常规时间内狂敛惊世骇俗的81分,引起球迷的疯狂热捧。部分科迷认为科比从此史上第一,因 此如果有其他球星的球迷列出事迹挑战,科迷总是说:“××算个毛,科比有81分”,最后竟然演化凡是很nb的事,不管和篮球有没有关,大家总是用“××算 个毛,科比有81分”来反驳,科比的毛八一的绰号得来如此。又因为在中国八一刚好是建军节,于是水木清华BBS网友BillieJean又给科比取了“毛 建军”的外号,属于毛八一的衍生。
2008年12月21日星期日
精神分裂
#你带着大山的气息土的味道,
#扑面而来,席卷我的身心
#我使劲扑进你的怀里
#寻找你出发时我留给你的泪水的气味
#找不到呵
#在坟起的胸肌下
#只能听到雄壮跳动的声音
#它全部占据我的味和嗅
#而你只会傻傻的笑
#然后拿出我说过很多次不喜欢的泥娃娃
#说特地带给你的
#再用力的吻我的颊和唇
#我便又迷失在那棕色的激情里
#
#回家了罢
#那些依旧的埋怨
#狗太温顺沙发太软
#我得意的笑
#就是不能让你过好日子
#你便将我背在背上
#硬给我讲那些路上的故事
#我不听我不听
#粗糙的旋律
#大山是盘古的刀砍出来的
#我只要在你的背上刻下记忆
#你便讲着
#我便假寐的听着
#直到那些悲伤慢慢溢满的我的眼睛
#延续到以后
#瞳孔里倒映出你行囊的背影
#才化成扑簌的眼泪
#等待下一次心情
可以确定,上周六下午我坐在床上是处于一种精神分裂的状态
2008年12月18日星期四
2008年12月17日星期三
2008年12月16日星期二
2008年12月14日星期日
做梦吧
在苏州图书馆泡了两天
书多得有点目不暇接的感觉,这两天主要看了两本书:欧美文学史和George Owell的一本短文集《我为什么写作》,太假了,感觉自己变得越来越文艺小青年,真好现象。
还看了奇幻世界,本质是还是通俗派读者,哈哈。
2008年12月6日星期六
2008年12月5日星期五
2008年12月3日星期三
十八禁--《尘缘》人物辞:古韵芳香*雷人胸膛
没看过《尘缘》的人怕是不懂
青衣:夜来小纪小二长,欲行房,雨浪浪。相顾无言,殷殷在身旁。犹有顾清宽玉
带,长夜漫,四人厢。
若尘:无人慰我铁龙阳,坐当庄,意彷惶。定海神针,无奈满春光。若个分身赐与我
,御三美,又何妨?
殷殷:昨夜星辰昨夜霜,死纪郎,又装腔。怕我恩师,逃难贱人床。对面小妖休猖放
,人有报,恶须偿。
顾清:紫薇星玑出六芒,上洋洋,下红桑。枕畔春云,前世梦一场。安得魂归今夜烛
,开玉乳,任君尝。
欢喜城
虽然如此,江湖中向往欢喜城的还是大有人在。每年的11月11号是欢喜城通过秘密渠道发布邀请的日子 ,一般直接邀请名额限制在二十个,除此之外欢喜城还发出一百个流动名额,这些流动名额以欢喜城特有的“水立方”镂金檀木薰香月明盒作为信物,到次年的11月11号再度收回,届时持有这些宝盒的人便可以无条件进入欢喜城。
于是即使与世隔绝,每年进入欢喜城的人还是不在少数。欢喜城的直接邀请名额一般都是江湖的名门望族,豪侠大师,这些人不是不屑名利,就是有家有业,一般不愿意进入欢喜城。但流动名额不一样,谁都可以通过必要的手段得到它,经过一年的流通,那些水立方木盒大都落到了江湖中恶名昭著的江湖败类手中,这些人为了躲避正道人士的追杀,费劲心力的追踪宝盒的踪迹,不择手段的想把它弄到手,因此伴随着宝盒的流通,江湖也掀起了一股股血雨腥风。
2008年12月2日星期二
午夜狂想
一 :回忆录
不得不承认,虽然很少,但人生确实存在着不可思议与巧遇。两天前我在南京火车站买票来苏州,正在人流中无所谓的排队,过滤掉所有的噪音后一个似曾熟悉的声音身边响起,正问同伴是否够钱买票。我下意识回头,蓦然发现是许久未见的大学同学。伊在天大读完硕士后到华为,在深圳折腾几个月到淮安,昨天到南京今天去上海,仅仅在南京站停留数十分钟,就在这里遇到了同样仅停留数十分钟的我。高兴和怀旧便开始充溢我们的胸膛,还带上一点点对不期而遇的惊叹。可惜相逢总是短暂,我们的火车马上就要出发,带着两人各奔前程。
二 :住宿
昨晚hellen带我到她的住所,不得不说和我想象中相差较大。
这是一座暗色调的建筑。建筑的后部光影全无,巨大的骨架后面投射出浓重的墨色,我随着hellen的脚步一头扎了进去,让黑暗把人吞没。让人惊异的是立在墙外的之字楼道,突兀的伫立在建筑的外侧,整个楼便像坐在枝头的猫头鹰,楼道就是那竖起的翅膀。楼里的过道也没有电灯,黑色一直延伸到房门口,然后才被一扇木板挡在了门外。
正所谓“灰满地,尘满墙”,这整个楼都透露出一股垂垂老矣的意味。但在某些方面也能让人兴奋。怀旧的人看着该有感慨满怀,这翅膀当是过去的见证;喜欢拍鬼片的我那同学估计会大呼过瘾,阴森古老这里两者皆备。我在上楼的时候磕在阶梯上一个趔趄,hellen便放肆的大笑,笑声在这楼道里空旷的激荡。
三 :无题-毛-kobe-建军-八一
艾未未那厮说:人生本来就是个悖论,我们都处在矛盾之中。虽然我十分否认他那怒放的发型,但对他这句话还是满同意的。
。。。。。。。未完成
2008年12月1日星期一
工作第一天
本公司为美国的cox company提供关于system,database方面的服务,我们通过网络来干一些细枝末节的看似高深却应该是没啥技术含量的事情。
恩,这就是今天某美女,据说是我们的project manager,但我老记不住他的名字,给三个新员工做introduction后我得出的结论,似乎我喜欢把自己放在一个穷苦阶级,以贬低自己做的事情来贬低自己。
接下来的一天都在忙着写个文本处理程序,好像公司里面就我一个写perl的,难道我又要如此孤单了么。心情也颇郁闷,因为不想过这种从早坐到晚的生活但为了赚点钱,别无他法。
本公司有个让我目前目瞪口呆的政策,每个工作日都需要学习英语,我不知道这是怎么产生的,但事实是课本员工自己掏钱买,商务英语100课,每天一课的学习,最后效果由本公司英语系的众mm们检查。想想我认真的学英语课文还是在大二年代,那快五年多光阴,且是为了过四级逼不得已。所以现在很想来个非暴力不合作,鉴于自己仅是新人,遂作罢。
还在担心要找不到房子,可能在办公室睡袋一晚。所谓峰回路转,晚上一同事说他要搬家,可以把房子转租给我,呵呵,其欣喜为何如。
恩,所以本来可以六点滚蛋的,在这里等到九点。
顺便可以说下公司的上班制度:
一周三天半,整天是从早九点到晚九点,半天是六个小时。
不过我新人,于是还是五天班,九点到六点。
希望自己能好好活下去。
2008年11月20日星期四
Great Perl Modules
http://www.perlfoundation.org/perl5/index.cgi?recommended_cpan_modules
http://perl.net.au/wiki/Recommended_Perl_Modules
http://wiki.perlchina.org/index.php/%E6%A8%A1%E5%9D%97%E6%8E%A8%E4%BB%8B
Parse::RecDescent (不推荐,太慢)
Parse::Yapp
Parse::Eyapp
perl-byacc
http://home.earthlink.net/~slkpg/
http://packages.debian.org/re2c thread safer lexer generator
http://packages.debian.org/lemon thread safer parser generator
DBI
Class::DBI
DBIx::Class
Rose::DB::Object
DBIx::Simple
Apache::PageKit
Maypole
Catalyst
Mason
Mojo
CGI::Application
CGI::Prototype
Gantry
Jifty
http://perl.apache.org/products/app-server.html
========================================================
Apache::DProf
App::Ack
App::Config
BerkeleyDB (比 DB_File 的接口更全面)
Bundle::Test
CGI
CGI::Minimal
CGI::Simple
Class::Struct
Clone
Config::General
cpan2dist
Cwd
Data::Dumper
Data::FormValidator
Date::Calc
Date::Manip (太庞大,不推荐)
DateTime
DBD::RAM
DBD::SQLite
Devel::Cover
Devel::DProf
Devel::Hide
Devel::SmallProf
Encode
ExtUtils::Installed
ExtUtils::MakeMaker
File::Basename
File::Copy
File::Find
File::Find::Object
File::Glob
File::Path
File::Spec
File::Temp
Filter::Simple
Filter::Util::Call
FindBin
GetOpt::Long
GetOpt::Std
Hook::Scope
HOP::Lexer
HTML::Seamstress
HTML::Selector::XPath
HTML::TreeBuilder
HTML::TreeBuilder::XPath
Imager
IO::AtomicFile
IO::CaptureOutput
IPC::Run3
List::MoreUtils
List::Util
List::Utils
Log::Log4perl
LWP::*
Mail::Mailer
Mail::Send
Markdown
Memorize
mocked
Module::Build
Module::Starter
Moose
Net::*
Object::Destroyer***
ops
PAR::Packer
Params::Validate
Parse::RecDescent
Path::Class
Perl::Critic
Perl::Tidy
perlcritic
POE
POSIX
ptkdb
Regex::Assemble
Regex::Common
Safe
Scope::Guard
SQL::Interp
Storable
Sub::ScopeFinalizer
Switch
Sys::Mmap
Template
Template::Extract
Term::*
Test::*
Test::Builder
Test::Builder::Tester
Test::Class
Test::Data::Array
Test::Deep
Test::Differences
Test::Exception
Test::File
Test::File::Contents
Test::FITesque
Test::Harness
Test::Kwalitee
Test::Memory::Cycle
Test::MockModule
Test::More
Test::NoWarnings
Test::NoXS
Test::Number::Delta
Test::Output
Test::Pod
Test::Pod::Coverage
Test::Simple
Test::Spelling
Test::Taint
Test::Trap
Test::Warn
Test::Without::Module
Test::WWW::Declare
Test::WWW::Mechanize
Text::Autoformat
Text::CSV::Simple
Text::CSV_PP
Text::CSV_XS
Tie::File
Time::HiRes
Tk
typesafety
uniread
Web::Scraper
Win32::AdminMisc
Win32::FileOp
WWW::Mechanize
XML::LibXML (不推荐用 XML::Parser, XML::XPath, XML::DOM, 推荐用 XML::LibXML)
XML::Rules
XML::Simple
XML::Twig
第四次摔跤
今天老同学来了,虽然这只是伊旅途的中点站,但也颇念旧情的腾出了十几个小时来探望下大学旧同学。当年毕业后,他们都留在了北方,就我孤身一人来到长三角的南京城。这些人们,两年多没见了。
伊对我这一年多的骑行生活颇感兴趣,我便从师兄处借了山地车给他,扑腾腾的带着“新人”上紫金山。
带他干点啥呢,若是骑天文台路登山似乎过于无趣,仅一条石板路而已。于是决定去表演越野,让伊看看我等骑车人是如何玩山地车的。
“龙脖子”,这是一个近两米的落差小坡,目测坡度有七八十度,右侧是枯树盘根怪石当道,左侧有羊肠小道尚可称为成为平坦。有图为证:
据说,事实也是如此,此坡考验的是车手的勇气。越野的新人,或有些骑行基础,看到这陡坡未行先胆怯者,老鸟们便如此劝慰:下坡时不用刹车,一放手便冲下去,到平缓的地带再减速,这是没有难度的下坡。想当年我第一次正是如此,后来再而三四,从未失手。
然而今天居然失手了,这让我到现在都感到甚是羞愧难当。鬼使神差的我居然冲到了盘根老树上,车子腾空而起重重的砸在地上巨大的反冲和惯性使我飞将出去,迎着大地摔倒在泥土落叶和碎石当中。
迅速检查身体各部分零件。胳膊大腿安好运转正常无不良反应,脑袋也还在脖子上。咦,脸上怎么火辣辣的,才想起今天没有带头盔,脸颊有轻度擦伤,黑乎乎的一片。
伊倒是紧张担心了一下。我颇为恼怒,反复向伊强调这个状况是绝对不应该发生的,于是执着的重来了一遍,果然成功,老天尚给留三分薄面。
想想,玩山地车这么久以来,这是第四次摔跤了吧,前三次都在遥远的一年前。第一次骑行,贡献初次两摔。那时何其的菜鸟啊,骑上头陀岭几乎就要了我的命,之后下防火道,此路当年还未曾修葺,碎石嶙嶙张牙舞爪散发森冷的笑。带我玩的师兄也是如此说不用刹车直接往下冲即可,但当我看到一巨石横卧于车轮正前方我胯下这牲口似乎也有失控的趋势时六神无主的把前后闸使劲一捏,前轮一头装上石头瞬间抱死,后轮继续向前冲从而飞腾而起,人车皆飞出丈外。这教训告诉我,高速下坡时前刹车是如何的碰不得。
接下来十分钟后奉献了第二跤,只是因为身体消耗太大由于颠簸把持不住车子而已。第三次摔跤与第一次情节雷同,不过换的是另外一条路,就此表过。
然而玩山地的车友们,谁没有狠狠的摔过呢,据我所知道严重的摔,南京大学有同学摔破了脾脏;我一师兄摔碎了肩膀,从此不再玩车;传奇人物丁丁,幕府山越野时从十米高的崖壁上摔下,居然分毫未损。而我亲眼目睹的有:
另一师兄,伟大的“龙脖子”上冲下,车失控而摔,车砸小腿上,严重内伤,半月走路不便,肿到小腿粗过大腿。
再一师兄,非下坡,貌似平路上一坑。反正是在我等前面领骑,突然没来由摔倒,破相,眼下破一长口。
某车友,青龙山上碎石路,速度太快车打滑而摔,一石子嵌入颧骨面皮之中,众皆不敢取下石子,怕血流不止,后送医院。
光华亭,号称紫金山最难下坡,那一日,强人纷纷表演,多数人半路便落马,所幸没有受伤。
山地越野谁未曾摔倒一二呢,数日前一起刷大街,一老车友聊起他膝盖上密密麻麻的缝针痕迹,他感慨的说,年轻的时候越野摔的,现在膝盖里面还有钢钉支持,一把老骨头,只能玩公路罗。
当然啊,这全身的疤痕便是你越野的痕迹,更是年轻的象征,无论过去的还是现在。那时,或这时,我们是如此的喜欢冒险,喜欢刺激,用山地车越野这青春。
2008年11月16日星期日
书评《秦腔》

这不是一本让我有一口气看完的冲动的书。
总的感觉秦腔想找一种文学构思上的突破,在这本书里面没有一个很明显的故事主线,所有的情节都是在一个疯子的眼中展开,前提假设了这个疯子无所不知,当然它不能无所不能。在这个“我”的眼中,这些破碎的事情组合起来,变成了整个“清风街”的故事,折射了九州下,三秦大地上一个普通农村在时代变迁下的变化发展。老贾写故事的能力没什么话说,靠大量如剧本对话就支起了这个庞大的框架,描述了一个个活灵活现的人物形象。
但如果说这本书主题是为了表现农村的变迁,那我坚持它不是一本优秀的作品,就像前面说的,这方面的主线描述太不清晰,几乎没有什么在改革下矛盾的正面描写,都是通过旁敲侧击一点点渗漏出来的,以至于看完这本书,印象最深刻的是秦家一院子的那些老老少少们,还有这个疯子对白雪的畸形恋情,秦腔被流行歌曲挤出历史舞台?农村劳动力缺失以致没人抬棺材?那都是细枝末节而已,似乎并没有上这个故事的主线。
这本书的有些描写方式被一些文学批判家以恋污癖与性景恋的名义大肆批判,比如这样的写法:
上善的眼睛里发了炎,用袖子粘一次,又粘一次,似乎眼里有个肛门,屙不尽的屎。但上善始终坐得稳,不像别的人一会儿出去上厕所,一会儿起来倒茶水,再是大声地擤鼻子,将一口浓痰从窗子唾出去
从一个单纯的读者角度来看,我很难接受那些嘴里吐出蛔虫,生个孩子没屁眼的情节,屎来屎去的写法。或许老贾认为这样渲染原始和粗俗可以起到一些出其不意的效果,某种“从肉体到精神的震撼”,但现实效果是看到这些让我至少给这本书的评价下一个档次。
或许,这本书可以改个名字,叫《那街,那人,那狗,那些破事》罢,这只是一个小村落的轶事而已。
2008年11月10日星期一
Cpan Class Collection
Class::Std
用来提供InsideOut Object,何谓InsideOut Object可参看fayland的一篇博文
http://www.fayland.org/journal/InsideOut.html
Class::Accessor;
Class::Accessor::Fast;
Class::Accessor::Faster;
快速创建类存取器
FindBin
找出当前perl scirpt的目录
Path::Class
多平台的目录工具
Net::SSH::Perl
ssh工具
use Net::SSH::Perl;
my $ssh = Net::SSH::Perl->new("192.168.100.11",identity_files=>["$ENV{HOME}/.ssh/id_rsa"]);
#my $ssh = Net::SSH::Perl->new("192.168.100.11");
$ssh->login("wxu");
print "Logged\n";
$ssh->cmd("touch z");
2008年11月9日星期日
有一只猪400斤,一座桥承重200斤,猪怎么过桥
酒是穿肠毒药,色是刮骨钢刀,财是惹祸根苗,气是雷烟火炮。
这四句话,说的是酒色财气这几样东西,千万不要沾,沾上就得惹事,轻则伤身,
重则害命。这不嘛,有一只猪,这天喝多了,歪歪扭扭往家里赶,迎面看见一座桥。他仔细
这么一打量,这地儿以前没来过啊……心里就发迷糊。书中暗表,怎么回事儿啊?这猪它不
是喝晕了嘛,两眼根本就看不清东西了,就低着头看着脚赶路,一不留神,走茬路了。
这猪心想,没来过就没来过吧,怎么回不是回啊。就往桥上走,还没等上去呢,旁
边过来一人:“嘿~~说你呐,站住!”就把这猪拉住了。这猪一瞧,怎么回事儿,我一没贪
赃,二没枉法,三不算酒后驾驶,你没事儿不让我走路干嘛?仔细打量,来的这人,长得一
般,穿得利落,是一套制服。怎么知道呢?上面明白印着一行字“看桥员”。
看桥员用手一指,这猪顺着一望,瞧见这桥上刻着四个大字“限重一百斤”。“瞧
见没,你……总有四五百斤上下了吧,你要上去,非把这桥压塌了不可。绕道吧,赶紧的,
走走走。”就轰这猪。
要不怎么说喝酒害人呢,要放往日,这猪也就绕道了,这又不是平常自己走的,绕
回原道就完了。今儿这猪喝高了,被人一轰,还上来脾气了。噢,你让我绕我就绕,那哪儿
行啊。瞧不起我,以为我胖,我就过不去了?今儿爷爷给你瞧个鲜儿。这猪伸手就把看桥员
拨拉到一边去了,后退了几步,奔着桥就跑过去了,眼看到桥边上,这猪较一力丹田混元气
,舌尖一舔上牙塘,脚尖一点,脑袋一晃,ri的一声,跳在空中。旁边过路的可看傻了眼,
哥哥大爷,嫂子弟妹,瞧见没有,空中飞人啊,哗~~~可热闹瞭。
看热闹的暂且不说,再说这猪跳在空中,还那句话,喝酒害人,怎么呢?本来这只
猪,是个练家子,出身可了不得,乃是水木社区粥客版的当家,跳过的大坑无数,轻功非常
了得,区区一座小桥,扭扭腰就蹦过去了。今天不行,今天它喝酒了,脚软,跳起来眼看着
还没到那一边就往下落,想起来了,噢,今天我喝多了,跳的时候劲儿没用够……那哪儿行
啊,噢,我砸下去,把桥砸塌了,好说不好听,丢人就丢大了,不行。想到这儿,这猪咬咬
牙,把压箱底的绝活拿出来了。
只见它,左后蹄一踩右后蹄,“蹭”的一声,往前窜了五尺,右后蹄再一踩左后蹄
,“蹭”的一声,又窜了五尺……正好落在桥的那一头。
这正是:
猪头三抄水,指,这猪顺着一望,瞧见这桥上刻着四个大字“限重一百斤”。“瞧
见没,你……总有四五百斤上下了吧,你要上去,非把这桥压塌了不可。绕道吧,赶紧的,
走走走。”就轰这猪。
要不怎么说喝酒害人呢,要放往日,这猪也就绕道了,这又不是平常自己走的,绕
回原道就完了。今儿这猪喝高了,被人一轰,还上来脾气了。噢,你让我绕我就绕,那哪儿
行啊。瞧不起我,以为我胖,我就过不去了?今儿爷爷给你瞧个鲜儿。这猪伸手就把看桥员
拨拉到一边去了,后退了几步,奔着桥就跑过去了,眼看到桥边上,这猪较一力丹田混元气
,舌尖一舔上牙塘,脚尖一点,脑袋一晃,ri的一声,跳在空中。旁边过路的可看傻了眼,
哥哥大爷,嫂子弟妹,瞧见没有,空中飞人啊,哗~~~可热闹瞭。
看热闹的暂且不说,再说这猪跳在空中,还那句话,喝酒害人,怎么呢?本来这只
猪,是个练家子,出身可了不得,乃是水木社区粥客版的当家,跳过的大坑无数,轻功非常
了得,区区一座小桥,扭扭腰就蹦过去了。今天不行,今天它喝酒了,脚软,跳起来眼看着
还没到那一边就往下落,想起来了,噢,今天我喝多了,跳的时候劲儿没用够……那哪儿行
啊,噢,我砸下去,把桥砸塌了,好说不好听,丢人就丢大了,不行。想到这儿,这猪咬咬
牙,把压箱底的绝活拿出来了。
只见它,左后蹄一踩右后蹄,“蹭”的一声,往前窜了五尺,右后蹄再一踩左后蹄
,“蹭”的一声,又窜了五尺……正好落在桥的那一头。
这正是:
猪头三抄水,轻过限重桥。
2008年11月8日星期六
猪头三一般的腾讯二面
果然马上就发腾讯二面短信了,是今天,周日。我还有诺基亚和搜狐的笔试,都冲突了,但鉴于腾讯是二面,遂放弃其他。
面试官,一个年轻的帅哥,先让我介绍了下自己。说实在我从来没特别准备过啥自我介绍之类的东西,于是噼噼啪啪开始将我现在中科院原来在天津大学啥玩意都是自学的,就这么一笔带过,看人家的眼神,似乎这个也不怎么重要。
然后hr同学问我有啥优缺点。啥优缺点啊,自褒自鄙有意思么,我脑袋里呼呼的抱怨,开始随便乱扯所谓的优点。到缺点的时候还真是脑子顿了一下,说了本次面试最大的所谓亮点:喜欢装酷,不喜欢搭理人。这下被hr抓到了,丫开始对我进行全方位的轰炸,装酷?居然不喜欢搭理人?这些都是职场上面不好的,改正改正之类,完全一副诚恳建议的姿态,但我心里估计他已把我给bs了。
也没有再问太多技术问题,一个是写shell脚本,如果有两个文件,分别为学号和成绩,学号和姓名,找出成绩前5的姓名。另外一个是一亿的数据,怎么找出最大的一万个,这个不会。
2008年10月30日星期四
创建可传递use strict的模块
use strict;
use warnings;
use Module_Name;
为了简化程序,可以将use strict和use warnings放到模块中传递
代码如下
package ABC;
use strict;
use warnings;
use base 'Exporter';
sub import{
strict->import;
warnings->import;
__PACKAGE__->export_to_level(1, @_);
}
1;
#!/usr/bin/perl
use feature ":5.10";
use ABC;
$undefined_var = "undefined var";
$ perl test.pl
Global symbol "$undefined_var" requires explicit package name at test.pl line 5.
Execution of test.pl aborted due to compilation errors.
2008年10月19日星期日
2008年10月16日星期四
山地情怀中的那些bt们
正所谓高山仰止,景行行止。
在山地情怀混这么一年,丁丁和孔雀,毫无疑问的属于这些bt人种。
丁丁此人未曾谋面,但却颇有耳闻,最常的,便是在腐败桌上谈起他的饭量,山地众元老们皆以无比钦佩的口吻说到,丁丁以前和我们吃饭,一瞬间四碗下肚,然后言曰没啥菜不吃了,且最近减肥。
孔雀有和他几次骑行,最深印象是一身白肉,怎么也晒不黑。要知道玩自行车的,一天在太阳下暴晒那是经常的事,于是这群人看着都这样,把袖子和裤脚卷起,黑白分明,下部是非洲人种,被衣服遮住的部分是正常黄种人。
但孔雀不一样,怎么看都是一个纯粹的白种人,一身白肉。
其他的印象的话,像洗衣板似的一块头发挂脑后;下坡的时候,特别一次在号称南京最难的下坡光华亭,轻盈得像羽毛一样的控车,还有就是踩不死的体能。
暑假期间,我看着丁丁在小百合上的游记游记骑行青藏线,当时感觉此人果然生猛,一天200多公里不在话下,而且颇有游侠风范,随便住工地之类的地方。然而回来后,发现丁丁在情怀版面上扔地雷了
丁丁:功亏一篑的古仁拉——预告片完
一上来便是一双被废掉的脚丫子。
接下来的贴子开始介绍他在西藏的野人生活:功亏一篑的古仁拉(全文完)
这完全是一段渺无人烟的探索,5天的时间,风雪,低温,野牦牛,文中提到的重见天日的感觉,让人不由感叹这个小伙子在寻找一种怎样的生活,难道这就是挑战极限和未知的乐趣?
冰川下的自行车
从来不知道玩车可以玩到如此疯狂的地步,走完了青藏线,我如井底之蛙一样把头抬得高高,仿佛天下英雄尽止与此,然而这笔记和图片告诉我,这是没有极限的征途。我在想,面对这些未知的高山,必然险恶的环境,我有没有勇气如他一般义无反顾的一头扎进去?
这小子现在还在西藏,一座座的追寻他未曾谋面的山川,不时在山地上给我们留下他的那些足迹,感动我们这些被城市压迫的人们。
丁丁出面,孔雀也出手了。
预告片:在祁连山的心脏
bt果然是类似的,同样的一个人,同样的工作在高海拔,同样的搞死搞残
好吧,我期待着你的续贴。
2008年10月13日星期一
在apache上运行Mod_perl
总算把mod_perl第一个页面配置出来了
写在这里
install忽略
1:创建Hello.pm
package Apache2::Hello;
use strict;
use Apache2::RequestRec (); # for $r->content_type
use Apache2::RequestIO (); # for $r->puts
use Apache2::Const -compile => ':common';
sub handler {
my $r = shift;
my $time = scalar localtime();
my $package = __PACKAGE__;
$r->content_type('text/html');
$r->puts(<<"END");
<HTML><BODY>
<H3>Hello</H3> Hello from <B>$package</B>!
The time is $time.
</BODY></HTML>
END
return Apache2::Const::OK;
}
1;
2:创建startup.pl
use strict;
use lib qw(/path/to/module/);
use Apache::Hello;
$ENV{MOD_PERL} or die "not running under mod_perl!";
3:编辑apache的httpd.conf或apache2.conf
加入
PerlRequire /path/to/startup.pl
SetHandler modperl
PerlHandler Apache2::Hello
4:startup.pl和Hello.pm的位置关系
/path/to/startup.pl
/path/to/Apache2/Hello.pm
perl Moose::Cookbook::Basics::Recipe2
package BankAccount;
use Moose;
has 'balance' => (isa => 'Int', is => 'rw', default => 0);
sub deposit {
my ($self, $amount) = @_;
$self->balance($self->balance + $amount);
}
sub withdraw {
my ($self, $amount) = @_;
my $current_balance = $self->balance();
($current_balance >= $amount)
|| confess "Account overdrawn";
$self->balance($current_balance - $amount);
}
package CheckingAccount;
use Moose;
extends 'BankAccount';
has 'overdraft_account' => (isa => 'BankAccount', is => 'rw');
before 'withdraw' => sub {
my ($self, $amount) = @_;
my $overdraft_amount = $amount - $self->balance();
if ($self->overdraft_account && $overdraft_amount > 0) {
$self->overdraft_account->withdraw($overdraft_amount);
$self->deposit($overdraft_amount);
}
};
知识点:
属性的类型可以是另外一个类的名字
新modifier before,他在父类函数之前调用定义的sub
相当于
sub withdraw {
my ($self, $amount) = @_;
my $overdraft_amount = $amount - $self->balance();
if ($self->overdraft_account && $overdraft_amount > 0) {
$self->overdraft_account->withdraw($overdraft_amount);
$self->deposit($overdraft_amount);
}
$self->SUPER::withdraw($amount);
}
2008年10月12日星期日
perl Moose::Cookbook::Basics::Recipe1
package Point;
use Moose;
has 'x' => (isa => 'Int', is => 'rw', required => 1);
has 'y' => (isa => 'Int', is => 'rw', required => 1);
sub clear {
my $self = shift;
$self->x(0);
$self->y(0);
}
package Point3D;
use Moose;
extends 'Point';
has 'z' => (isa => 'Int', is => 'rw', required => 1);
after 'clear' => sub {
my $self = shift;
$self->z(0);
};
....
# hash or hashrefs are ok for the constructor
my $point1 = Point->new(x => 5, y => 7);
my $point2 = Point->new({x => 5, y => 7});
my $point3d = Point3D->new(x => 5, y => 42, z => -5);
和perl5里面非常相似,类都放在一个声明的package里面,use Moose自动为我们添加use strict和use Waring,同时导入缺省的函数和关键字,并自动创建构造器
第一个关键字
has 'x' => (isa => 'Int', is => 'rw', required => 1);
为类创建一个名为x的属性,isa代表这是一个Int类型的变量,rw代表可读写,required代表创建类的实例的时候,必须提供这个变量值。
之后可以创建类的方法了,它只是一个子函数而已
sub clear {
my $self = shift;
$self->x(0);
$self->y(0);
}
借着来我们定义了子类Point3D,在子类中通过关键字extend来声明父类
extends 'Point';
extends和use base的功能很像,但有点不同的是extends覆盖了@ISA数组,而use base是把参数添加到@ISA数组
接下来创建类Point3D的新属性x
has 'z' => (isa => 'Int', is => 'rw', required => 1);
这和x,y没什么区别
after关键字声明了Moose的一个特性:方法修改器
after 'clear' => sub {
my $self = shift;
$self->z(0);
};
当从类Point3D中调用clear是,这个定义的函数会运行,之所以称为关键字after,是由于这个修改器在真正定义的函数后在被调用的。
从某种意义上来说这就是一个函数的继承
我们当然还有其他的方法做到这些,因为这是"perl"
比如:
sub clear {
my $self = shift;
$self->SUPER::clear();
$self->z(0);
}
再比如使用关键字override
override 'clear' => sub {
my $self = shift;
super();
$self->z(0);
};
据说是可以让你像ruby一样使用父类函数,可惜不懂ruby
然后就可以使用我们所写的类了
my $point1 = Point->new(x => 5, y => 7);
my $point2 = Point->new({x => 5, y => 7});
my $point3d = Point3D->new(x => 5, y => 42, z => -5);
注意:Moose里面的类都是一个hasn引用
所谓脚注:
1:Moose定义的数据类型
很多,去这里看 Moose::Util::TypeConstraints
2:Moose的extends支持多重继承
3:没看太懂,大约是使用某种方法Moose可以支持非hashref类型的类
文档支持在这里 Moose::Util::TypeConstraints
小丹阳,禄口机场,150公里
http://www.xici.net/b30523/d78648713.htm
不行了不行了,昨天回来到现在,大腿还是一直酸痛,两个月不骑退化了太多。
总结昨天的活动,就是刷大大马路,这150公里,路况好得让人惊奇,几乎都看不到什么起伏,没有任何下坡,也就没有任何休息腿部的机会。前面三辆公路车在飞飙,后面的山地车气喘吁吁的追得辛苦。我发誓这种刷大马路的活动再也不掺和了。
路线大约是这样的:从中华门出发,到江宁,到桃吴镇,到丹阳镇,到博望县,再到禄口机场返回。
几点趣事:
人数十二,三两公路,其余山地,光头胎山地胎大小不等,很不幸我看起来是车胎最粗的那位。但其中还有一个骑ATX660,这车放在5,6年前还能用吧,现在骑着咔嚓声不绝于耳,终于到小丹阳他以两年没动体力不支先回家了。
定点腐败很成功,一堆人搞了一堆酒,就连我这两年没碰过酒精的也来了一杯。话说搞自行车的都是吃东西的猛男阿,最后一桌菜只剩下汤头,还有人意犹未尽的在里面捞残羹冷炙。
在机场打飞机。。。好吧这很猥琐,但当时的情况就是一堆人围着飞机拍照然后叫嚣这打飞机啦打飞机啦,并很骄傲的说本次骑行名为打飞机之旅。
哈哈哈哈,公路车在大平路上三次暴胎,我看你丫骑得快!
伟大的西瓜,伟大的西瓜,虽然它要价两块三,一个就花了我们 24,但它在我几乎要倒下的时候赐予我力量,剩下的三十多公里一口气到屋,作用堪比兴奋剂阿。
恩,再也不掺和这种刷大马路的事情了。
2008年10月8日星期三
windows下安装模块的一些问题
但ppm提供的模块很有限而且相当的过期,所以还是使用cpan上面的包直接安装比较靠谱
1:使用nmake来代替linux make
http://download.microsoft.com/download/vc15/Patch/1.52/W95/EN-US/Nmake15.exe
从上面link中下载nmake15.exe,然后运行生成nmake.exe和nmake.err,将它们拷贝到perl安装目录的bin目录下面,一般是c:/perl/bin
2:使用vc的c编译器
如果是用c写成的模块,需要c编译器,一般是C:\Program Files\Microsoft Visual Studio\VC98\Bin\CL.EXE 将这个目录加入到windows的PATH变量中
具体是右键我的电脑->属性->高级->环境变量里面的系统变量
3:使用vc的库文件
perl.h需要很多库文件,在vc的include目录下,此时
运行
C:\Program Files\Microsoft Visual Studio\VC98\Bin\VCVARS32.BAT
即可是用这些文件
2008年10月5日星期日
perl tk笔记: Text widget
$text = $parent->Text( [ options ... ] )->pack;插入内容
$text->insert('end', "To be or not to be...\nThat is the question");最常见的用法是创建一个Text widget,把从文件读来的内容置于其中$text = $mw->Scrolled("Text")->pack( );
open (FH, "chapter1") || die "Could not open chapter1";
while () {
$text->insert('end', $_);
}
close(FH); 一些options
line spacing
-spacing1:指定新段落前空出行的大小
-spacing2:如果一行文字超过text widget大小,则自动换行,本选项指定行与行之间的间隔
-spacing3:段落结束后行空间大小
tabs
定制tab的大小
如 -tabs =>[2,'center'] 两字符大小,后面的center是什么意思没搞明白
文本索引
定位text widget中文本位置的方法
基本索引值
n.m 第n行第m个字符,注意字符从零开始
@x.y 离坐标x,y最近的字符
end 文本结尾,\n后面
mark
tag.first
tag.last
$widget
$image: 以上两个代表widget和image的位置
索引修饰符·
+ | - ] n [ chars | lines ]
+-n字符或行
linestart
行首
lineend
行尾
wordstart
单词开始字符
wordend
单词结束字符
关于tag
tag是预先设置的文本属性,在插入文本的时候可以使用它
一个例子:
$t = $mw->Text()->pack( );添加tag
$t->tagConfigure('bold', -font => "Courier 24 bold");
$t->insert('end', "This is some normal text\n");
$t->insert('end', "This is some bold text\n", 'bold');
$t->tagAdd('tagName','startPosition1','endPosition1','startPositon2','endPostion2',.....);
如:
$t->tagAdd('bold','sel.first','sel.last') if $t->tagRanges('sel');
sel是内置的特殊tag
sel.first/sel.last表示当前选中文本的开始和结束位置,我们使用tagRanges('sel')来判断是否有被选中的文本。
获得当前选中文本
$sl = $t->get('sel.first','sel.last') if $t->tagRanges('sel');
或者
$sl = $t->getSelected();
2008年10月4日星期六
perl tk笔记: scrollbar滚动条
1:同时创建widget和scrollbar
$widget = $parent->Scrolled('Widget',
-scrollbars => 'string' [, options ]);
-scrollbar 的值可以是"n", "s", "e", "w"; or "on", "os", "oe", "ow"代表此滚动条出现的方位
Configure
$lb->Subwidget("xscrollbar")->configure(-background => "green");
如果对一个不存在的scrollbar进行配置,则出错
2:单独创建scrollbar
$scrollbar = $mw->Scrollbar([ options ...])
当创建完一个滚动条之后需要和其他widget联系起来
$scrollbar = $mw->Scrollbar( );
$lb = $mw->Listbox(-yscrollcommand => ['set' => $scrollbar]);
#将scrollbar和listbox widget相关联
$scrollbar->configure(-command => ['yview' => $lb]);
#配置点击scrollbar时改变listbox的内容
#Pack the Scrollbar first so that it doesn't disappear when we resize
$scrollbar->pack(-side => 'right', -fill => 'y');
$lb->pack(-side => 'left', -fill => 'both');
scrollbar和其他widget的整合
如前所示,程序通过command选项告诉scrollbar和哪个widget关联,command的值必须是xview或yview,
分别代表scrollbar出现在水平方向和垂直方向的两种情况。
有三种形式的调用
$widget->xviewMoveto(fraction);
$widget->xviewScroll(number, "units");
$widget->xviewScroll(number, "page");
似乎我们并没有必要搞清楚是如何工作的
2008年9月29日星期一
perl tk笔记:button
button/checkbutton/radiobutton
checkbutton放在一起可多选,radionbutton放在一起单选
每个checkbutton提供是否选中的1或0,而多个radionbutton仅提供一个变量,选中后体现为变量的值。
OPTIONS
-command
$b = $mw->Button(-text => 'Blue', -command => [\&change_color, 'blue'])->pack;
[]代表后面还有个参数?我猜的
-variable
$mw->Checkbutton(-text => 'Print Header', -variable => \$print_header);
注意传递的是一个引用
-value
$mw->Radiobutton(-text => '$' . $_, -variable => \$group1, -value => $_)->pack(-side => 'left');
对于radionbutton,还得传递一个value值给variable
-textvariable
$mw->Button(-textvariable => \$count)->pack(-side => 'left');
$count的变化会立刻显现出来
-bitmap
$mw->Button(-bitmap => 'error', -command => \&handle_error)->pack;
很多内置bitmap
-image
$image = $mw->Photo(-file => "bigredbutton.gif");
$mw->Button(-text => 'Exit', -command => sub { exit },
-image => $image)->pack;
使用image必须先创建image widget,如果text和image同时被指定,只会出现image。
-state => "normal" "disabled" "active"
disable一个button
-relief => 'flat''groove''raised''ridge''sunken''solid'
普通凹槽突出突出的边框凹陷实线边框
-width => x, -height => y
改变button大小
-underline => N
在text的第n个字母下划线
$b->configure/$b->cget
$state = $button->cget(-state);
$text = $button->cget(-text);
configure用来配置button显现
cget用来获得选项值
$button->invoke( );
运行button的command指定函数
perl tk笔记: fonts
使用字体最简单方法:
perl myTkApp.pl -font "Times 12"在linux中可使用xlsfonts来查看安装的字体,使用X Logical Font Descriptions (XFLD)来描述一个font如:
*-helvetica-bold-r-*-*-*-240-*-*-*-*-*-*每个字段的意思为
-foundry-family-weight-slant-sWdth-adstyl-pixelsize-pointsize-resx-resy-spacing-avgWidth-registry-encoding.
font基本属性
family:font的名字
size: 以point为单位的大小,point=1/72inch
weight:粗体
slant:斜体
underline:下划线
Overstrike:中划线
Font的使用:
$code_font = $mw->fontCreate('code', -family => 'courier',以上创建名为code的font,在button中使用。 -font选项可以是font名字也可是$code_font变量,还可以是一个匿名数组的引用如:
-size => 12);
$mw->Button(-text => "Show Code", -font => 'code');
-font => ['courier', '14', 'bold']。当不想使用名字在fontCreate里面忽略。
$mw->fontConfigure($code_font, -family => 'Verdana');改变font属性使用fontConfigure
Font操作:
一旦创建了一个font,就能够使用fontActual查看它的属性
%big = $mw->fontActual('bigfont');
$size = $mw->fontActual('bigfont', -size);
使用fontDelete来删除font定义,此时已经使用此font的widget不受影响。
列出系统字体
@families = $mw->fontFamilies;列出程序定义过的字体
@definedfonts = $mw->fontNames;
2008年9月28日星期日
perl tk笔记: 布局管理
- -side => 'left' | 'right' | 'top' | 'bottom
- Puts the widget against the specified side of the window or Frame
- widget的的方位
- -fill => 'none' | 'x' | 'y'| 'both'
- Causes the widget to fill the allocation rectangle in the specified direction
- 拉伸的方向,x轴,y轴
- -expand => 1 | 0
- 配置rectangle是否拉伸,注意不是widget
- -anchor => 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w' | 'nw' | 'center'
- Anchors the widget inside the allocation rectangle
- 锚定widget的方位,上北下南左西右东
- -after => $otherwidget
- Puts $widget after $otherwidget in packing order
- -before => $otherwidget
- Puts $widget before $otherwidget in packing order
- -in => $otherwindow
- widget一般pack到创建它的区域中,此选项可改变widget的出现位置
- Packs $widget inside of $otherwindow rather than the parent of $widget, which is the default
- -ipadx => amount
- 直接控制widget的大小
- Increases the size of the widget horizontally by amount
- -ipady => amount
- Increases the size of the widget vertically by amount
- -padx => amount
- Places padding on the left and right of the widget
- 边框
- -pady => amount
- Places padding on the top and bottom of the widget
这个是Tk中的一个概念,当一个widget,此控件占据的空间按pack的规则进行延伸填充到window边缘或者碰到其他的widget rectangles为止,这就是Allocation Rectangles
pack(-side =>top)顶部的矩形
这样便可以理解expand 和fill选项了
unpack一个控件
只是unpack,不是destory
$widget->packForget( );如果重新pack的话会出现在所以pack的最后
获得控件的pack属性
@list = $widget->packInfo( );获得控件列表
%packinfo = $widget->packInfo;
@list = $parentwidget->packSlaves( )
2:grid
grid意为格子,它的用法和html中的table非常类似
grid选项
The rest of the options are similar to those used with pack:
- "-"
- A special character used in the grid widget list. Increases columnspan of the prior widget in the widget list.
- 增加widget所占列数目
- "x"
- A special character used in the grid widget list. Leaves a blank space in the
- grid.
- 标记此区域为空白
- "^"
- A special character used in the grid widget list. Increases rowspan of the widget in the grid directly above it.
- 增加widget占行数
- -column => n
- Sets the column to place the widget in (n >= 0).
- -row => m
- Sets the row to place the widget in (m >= 0).
- -columnspan => n
- Sets the number of columns for the widget to span beginning with -column.
- -rowspan => m
- Sets the number of rows for the widget to span beginning with -row.
- -sticky => string
- Sticks the widget to string sides. String contains characters n, s, e, or w.
- 向string代表的方位拉伸
- -in => $otherwindow
- Indicates the widget is gridded inside $otherwindow instead the parent of $widget.
- -ipadx => amount
- $widget b ecomes larger in x direction by amount.
- -ipady => amount
- $widget becomes larger in y direction by amount.
- -padx => amount
- Places buffer space equal to amount to the left and right of the widget.
- -pady => amount
- Places buffer space equal to amount on the top and bottom of the widget.
使用gridColumnconfigure和gridRowconfigure来配置行列参数,它们都接收行或列的序号作为第一个参数,可用选项有:-weight,-minsize,-pad,不能用grid来设置它们
%column_configs = $mw->gridColumnconfigure(0);返回当前参数如: -minsize 0 -pad 0 -weight 0
weight:看半天没懂啥意思
只知道有一个效果:当设置为0时widget不会随窗口的resize而变化大小,设置为1就可以了。
minisize: 设置最小尺寸
pad:改变widget周围大小
获得一个cell的大小
($xoffset, $yoffset, $width, $height) = $master->gridBbox(0, 2);删除一个widget
如pack $widget->gridForget
总行列数:
($columns, $rows) = $master->gridSize( );
所有grid子widget
@slaves = $mw->gridSlaves( );这个方法也接收行列号作为参数返回那里的widget
perl tk笔记:hello world
hello world!Tk都有一个MainWindow,最后使用MainLoop来运行窗口
#!/usr/bin/perl
use strict;
use warnings;
use Tk;
my $top = MainWindow->new();
$top->title("Hello World");
my $button = $top->Button(
-text=> 'Done',
-command => sub{exit 0}
)->pack();
MainLoop;
要新建一个widget,都是使用$top->Widget这样的方式,注意第一个字母大写,
如果不是大写表明是属性
关于pack和Tk的管理
任何一个widget都可以使用pack()添加都mainwindow里面,除此之外Tk还提供有 grid, place,form来进行几何管理
一旦使用了pack来提交widget,就不能再直接使用grid等其他方式,此时应该放在frame里面或其他
关于exit
一般使用exit作为退出时的回调函数
但Tk也自己定义了一个函数叫destory,可以使用$top->destory来调用,结果删除MainWindow并返回命令行,因此可以做一些善后工作。
2008年9月23日星期二
青藏线之旅:D14,终至拉萨
但其实也不简单,这段路下午基本上就是顶风,风向在中午的时候改变,而且路况是被称为搓衣板的起伏路,几公里上坡几公里下坡的,这样连续来几个上坡,突然崩溃的可能性还是蛮大。
首日从安多到那曲139km,没啥故事,翻过申格里贡,和芜湖的老昂成了搭档。老昂是搞铁人三项的,据说全国都狠有名,经常拿冠军。我和他的速度比较匹配,一起走相当惬意。
第二天从那曲到当雄,路牌是165km,到后来码表上显示是173km。骑得蛮崩溃的,风力太大了,又要爬坡。这时老昂显示了他铁人的风采,把我远远的摔在了后面,不过风力一过我死命赶,还是撵上了他。早上买八宝粥当中餐,打开一看是坏的,郁闷。
第三天我们准备一大早到那木错看日出的,5点钟就包了个车出发。倒霉的事情发生了,司机是个新手,水箱里面居然没有加好水,爬山的时候开锅了,走一截停一会,一直到里那木错湖还有十几公里远的时候彻底歇菜,车子启动不起来,此时路上来往的车子很少,有的几辆都是满载,一行人在那里是进退两难,后来司机搭车回去叫车了,我们还呆那,再后来路过一辆空车,我和老昂,老盲花30快钱往回走,其他人还想看那木错,就没有一起。我的风格是行程不能改变,所以没去那木错也无所谓。下午还继续赶路,到羊八井。
说到羊八井可能印象都是温泉,我也来提个地方,羊八井有国家宇宙线观测实验室,就在小镇后面,里面有中日意合作的两个大型地面簇射阵列,用来接收和探测外太空过来的高能宇宙粒子,想当年我毕业设计做的就是羊八井试验数据的分析处理以及后续理论工作,不过现在都忘光了哈哈。那地方看守也不严密,倒是出乎我的意料,赤裸裸的看上去谁都可以进去。
温泉现在建起了度假村,98元/人包住宿,当天我们被当地人忽悠,说不能住宿就没过去,第二天才告知可以住,但只有这一种消费方式,有几个后来过来的便决定再那再住一天。
这天在路上还遇到个日本人,从泰国骑车,经过老挝到中国,已经骑行有八个月。那家伙被晒得有点不成人形的意思,脸部没有被帽子遮到的地方全黑,还隐隐透出青色,鼻子下面还有小肉瘤,看上去小有点恶心。他也不惮忌高原的紫外线,直接短衣短裤骑行,所以小腿小臂都成焦炭了。这家伙骑得慢,车据说人民币一万,前轮上面还挂两个包,装备与我等大不相同。
最后一天就是到从羊八井到拉萨了,仍然风力很大,大下坡骑着也不爽,好歹只有75km,加上进城的十几,却也很快就到目的地。入住在布达拉宫后面的行者驴舍旅馆,老板很好,老板娘做菜手艺别提有多棒,而且吃饭便宜,强烈推荐这个地方。
青藏线之旅:D13,翻越唐古拉山
还好,借在沱沱河保护站的工作人员金口,天气真的一直不错,小阳光,暖暖的适合骑行。但路况并不好,坑坑洼洼的。一行十一人出发,我居然是冲在最前面的那个,这的确让我有点所料未及。在南京活动的时候,我经常被所谓强人hapi,hema之类远远拉在后面,所以一直认为自己是个小弱,当然木木就更加小弱了,现在看来,不是我太弱小,而是人南京这边人太强悍阿。
后来十二点前我第一个到了山顶,又有一段泥沙路,三辆大卡车从身旁疾驰而过,卷起千堆灰阿,我便消失在这片云里。到所谓唐古拉山路牌5231下正十二点。
山顶上的人出乎意料的多,有一家藏民十五口,男主人在晒着大片从雪山上摘下的雪莲花,更多的还是游客,开车上来的人一群群的,手里拿着照相机在不停的咔嚓。后面的车友也一个个赶到了,到一点后才完全上来,之后停下来的还有一波空军部队。我们在山顶的牧民家里想尝尝酸奶,一小杯五块钱,牦牛奶也是这个价格,酥油茶一块,蛮贵的。酸奶不一定每个人都吃得惯,反正我吃不下,太酸了,不过据说营养丰富,牦牛奶远没有在二道沟藏民家吃得香,和这家人磨了磨,每人免费喝了碗酥油茶,感觉像洗脚水,晕。
小孩子们还是围着要东西,五秒钟就对人说一句你好,那意思就是拿点东西来吧。我心存不爽,啥都没给,这群人怕是被惯坏了。不过木木喜欢给,把身上的沙琪玛全部奉献出去,搞得自己午饭没着落,只好来抢我们的。
磨磨蹭蹭到两点才下山,这时终于有了点高原反应,头特别痛,脑子就像一块大石头,在颅腔里撞来撞去,特别一颠簸就更加难受。
更加没有料到的是小唐古拉山远不如前面说的容易,下唐古拉就颇为不爽,大卡车一辆辆的在路上,速度快不起来,还有点侧风,没有一点冲下坡的快感。小唐古拉山叫做头二九山,海拔也有5190m,爬得我们好辛苦阿,连绵不绝的大坡。不过俺又是第一个上山顶的,有了前面头痛的教训,没呆太久,等三个人过来就下去了。
下山路逆风,骑着挺不舒服。路上碰到一个大姐,传奇阿,强悍阿,38岁,骑一辆普通自行车,去年9.20出发,到现在差不多一年了吧,近似徒步的走新藏到拉萨,又从青藏出去,目的地在内蒙的呼伦贝尔。为啥说她近似徒步,车头上一个大包,装的是瓜果蔬菜,一个猪头大,车后是房子一样的一个包,衣物帐篷之类,据她说这样的装备情况平路不可能骑得动,就下坡还能溜达下,瓜果蔬菜直接生吃,一天走20-30km,最多50,那是有大下坡的情况。真nb人阿。
大约19点到了安多,找了加旅店住下。这时离拉萨靠近,开始有点紧张气氛了,整个晚上,警车巡视无休。
2008年9月20日星期六
青藏线游记:D12,到达唐古拉兵站
抬头看看天,居然有阳光。旁边的工作人员说这要运气好,一直到拉萨都天晴,要不好的话下午就下雨,这地方天气多变,最多一天有48场雨。
加上武汉理工大学的,一伙人就这么出发了。总算小伙子们有速度和我匹配的,不再一个人冲在前面了。天公也算作美,虽然有时候到一朵乌云下会有小雪,但都不长久。60多公里的骑行,很快便到了沱沱河,所谓长江源。
一路景色都是那样,草原啊山啊雪啊,而且沱沱河除了有个长江源的称号外也没什么好看的,水相当浑浊,城镇也建立在这条河的周围,总之一点感觉都没有,我随便看看就跑过去了。南京的乐乐说一定要在沱沱河里面撒泡尿,木木完美的完成了这个任务。
今天赶路是到不了唐古拉兵站了,还有一百四十多公里。我和木木决定搭车赶过去,这时武汉的一个车友说他们的两个人现在在雁石坪了,他准备赶过去会和,决定一起搭车,于是我们又多了一个,叫他lei吧。
等了好久终于出现了一辆长途客车,从格尔木到拉萨的,三个人到兵站140公里开口就是400块,我怕他是想钱想疯掉了,最后砍价以120成交,车扔到后备箱里,车里面的被褥那是相当的脏。一路顺利到兵站。
到兵站居然发现有一大拨人在这里汇聚,在格尔木见到的芜湖五位,两位内蒙古工业大学的,一位北京的,加上我们仨,十一位,算是一个大团体了吧。后来从反方向上来个川藏进青藏出的车友,腰里别着一瓶白酒,太他妈的潇洒了,据他自己说是每天都喝酒,越喝劲越足,在高原上,岂一个猛子了得。
唐古拉这里有个野生温泉,在草原的一个孤零零的破房子里面。天黑下雪,我们后来的四个一起过去感受40度水温的享受。那个房子顶都是通的,雪从洞里还能飘下来,里面是一个2*2的小池子,天太黑,我们也不知道热水是从哪里冒出来的。反正都是大男人,一个个脱得精光跳了下去,我靠,不要太爽啊,刚下去的时候有点烫,但一会就适应了,美美的躺在水里,全身几乎都酥软了。
但这个温泉不能泡太久,不然会头痛,容易出现高反,反正我泡了会就受不了,头晕,身体发软,上岸后几乎都站不太稳。反爬青藏的朋友直呼乖乖了不得,这玩意还真是有反应。不过这个小温泉却给了我以前从来没有过的体验。
住的不是兵站,那地方要60块每人的住宿费,不划算,在山下的小旅馆住,十块,虽然条件差了点,就是一张床一个被子,但这种地方,还能有何所求呢?
青藏线游记:D11,崩溃的风火山口
起来的时间是七点多,到八点出发找早餐,发现镇子上所有饭店都没开门,没办法,只好到唯一开着的商店里求老板给泡了碗方便面。吃着60度的水温泡的方便面,一阵阵反胃,但没办法,为了有点能量补充,我愣是硬着头皮把这罐面吃完了。木木可不行,叫老板给煮了下,还是没有吃完。老板给检查了下天气,说这个雪马上就会停的,后来的事实证明他是个蹩脚的预测家,大雪一直下到下午两点多。
果不其然,出门刚几公里就碰到了泥浆路,我们以最慢的速度骑行,但泥浆还是四处飞溅到了身上和鞋上,车也开始了泥浆浴。在第一道泥浆路前遇上了第一个车友停在路边,来自山东,却是从浙江骑行过来的,长长的头发,黑炭似的皮肤,骑了有一个多月。他说自己现在有点高反,呼吸急促,在休息,我们便聊了会,后说一起走吧,但他马上又停下来了,我们在前面不知怎么回事。过了泥浆路后发现有点前胎迅速的在漏气,下来检查一看,一个硕大的玻璃碴扎在了外胎上面。木木赶上来一起帮忙换上备胎,怕外胎出事还在外胎内部贴了个补胎片,这过程山东大汉也赶上来呼啸而过了。
接下来的泥浆路就有点郁闷了,一堆大卡车堵在路中央,骑车子没法过去,我们小心翼翼的推车,但一不留神还是一脚就踩在了泥浆里面,顿时到脚腕处全湿透了,当时还没有感觉到冷,但到了后来爬风火山,雪下得愈加密集,风也吹得紧,山上温度越来越低,渐渐的就感觉到湿透了的手脚开始冰凉发冷,到后来基本麻木,感觉全无。上坡路蹬得辛苦啊,我只记得四周是大雪纷飞,眼前是一座座被白雪覆盖的山包,心里盼着过了这个山头应该就是山顶了吧,一转过去又一个山头出现了,当即就想崩溃,但咬咬牙还是坚持着一直骑行,也不记得是在山路的哪个位置从一个帐篷里冲出两只黑狗,追着车狂吠几十米远,我都没有力气加速摆脱,只能一直保持原来的节奏骑行,并不时看着两只狗头在脚后跟飘来飘去,但居然后来一直都能坚持下去,路上也没有休息,这样来来回回在绝望和痛苦中挣扎,我最后终于爬上了风火山口,而该死的大雪还在一直下个不停。到了山顶,直接往地上一躺,的确是累趴下了。木木后到,崩溃中。
后来和木木一起下山,吹得人更加麻木,到二道沟才86km,两人都感觉不行了,冲到一家藏民店里,劈头就问,有烤火的炉子么,坐在旁边一直烤火到死。
这家藏民是我路上见过最好的了,一家四口,夫妻,奶奶和一个刚会说话的小孩。小孩吃的是牦牛奶,他们说这都是买不到的,木木发挥他与人交流的特长,成功的攀上朋友后老板娘给我们两每人来了一碗热气腾腾的牛奶,味道浓郁而清香,至今回味啊,后来在唐古拉山上面买的5块一碗,远没有这种感觉。小孩子也很逗,由于从小被奶奶带大,就只和奶奶亲,会说话也只是一直叫奶奶,哭闹也只要奶奶一过来就停止,可爱的小姑娘。木木又开始唠叨家常,这真是他的强项,这点比我厉害太多,我都一直不怎么开口,很快他和老板也成了好友,开始互相研究相机的使用,而我在路上拦车,准备搭车到沱沱河,我们是抱着不能耽误行程的想法。
但终究没有拦到车,山东车友也过来了,烤火后去先去吃东西。老板帮我们联系在外面追踪藏羚羊的可可西里沱沱河保护站的员工,让我们今晚就住那个地方,据说能免费,呵呵。
我们后来也去吃饭,山东车友此时已经找到一家小旅馆住下。之后回来的时候又意外的遇到了一拨来自武汉工业大学的车友,他们一行八人,七男一女,一男高反,一女体力不支,已经坐车先去沱沱河。我们在便在一起聊天到很晚。
晚上沱沱河保护站的员工回来,却也出现个小伙子像我们要二十块的住宿费,说不可能免费,索南达杰还四五十呢,颇让人不爽,最后砍价到十块,我和木木住下了。
青藏线游记:D10,翻越昆仑山
西大滩出发路真烂,到处都是坑坑洼洼的,加之我的前叉没有锁死,骑着特别费力。天气延续了昨天的状况,阴沉,刚出发便下雨,走了十几公里到昆仑山下,居然下起雨夹雪,没见过世面的我当时就想坐车了,发短信问南京的朋友,原来这里下雪再正常不过。
这样的天气状况让人崩溃,骑车自然是特别累人的,看到路旁大卡车也是慢慢的吃力的爬坡,我伸出咸猪手扒上了一辆,爽啊,顿时除了手之外全身轻松。路上下坡时看到前面是大坡,我也没有放手一直扒了过去,速度冲到40,想想蛮后怕的,要是出危险一切就玩完了,好在路段比较平整,没有出问题。
之后扒着车几乎到了昆仑山顶,直到路上有坑没放手小摔一跤才停下,没受伤,万幸,以后看到路不平我就放手,这叫经验教训。面前是青藏铁路的高架和昆仑山隧道,雄壮威武,感慨油然而生,国家修这个路是何其困难啊。我才拍了一些照片,就被出现兵哥哥叫住说不让随便拍,检查我的相机把有他们哨所的照片删掉了。木木也扒着车赶上来,一直赶到我的前面。
之后的路没有之前的陡,我很快赶上木木,慢慢的朝山顶进发,不过到前面一看,傻眼了,一条烂泥路跃然出现在眼前,大卡车都停在旁边,堵了好长一节,问问才知道109国道近年大修,要敲掉水泥重新筑造,以后这样的路段还会不断出现。没办法,我和木木只好下来推车,慢慢地朝山顶进发。
费尽力气到达山顶时,烂路终于结束了,到海拔4817的路牌下,我们两都显得很兴奋,在公路上大呼小叫,左蹦右跳,只想把全身的疲累都甩出去。可可西里的路牌就在眼前,昆仑国家地质公园的路牌就在眼前,更广阔的山坡和草原就在眼前,我想应该有理由激动,在这里我们拍了很多照片,呆好久才下山。
下山路大坡,我们都创造了最高时速,我62他65,可见他的车性能比我的好。显然,我只是2k的入门山地车,他的车3k多。到达索南达杰保护站时显示为86km,此时又下起来大雨,我们便想在这里住宿,就一个藏族小伙在里面,拽得很,态度极其不友好,要价30块每人,要命的是居然没有吃的提供。来之前我问过南京的车友说这里有吃的东西,两人都没有带补给在身上,这怎么能住呢。我两各自翻翻行囊,我一个咸鸭蛋俩个小笼包,他两根香肠,互相吃了点,我们被迫赶往五道梁。
出发后雨就停了,出太阳,而且不烈,感觉正适合骑行,我开始在前面飙车,记忆中应该是下坡居多,一会木木就拉到后面看不到影子,路上看到野毛驴和藏羚羊,藏羚羊胆子太小,看到人过来很快就跑走了,拍照时就只剩下一个小点,毛驴倒是很配合的在路旁摆pose。走了145km,19点到了五道梁,骑得很爽,木木还不见人影。
在饭馆里点菜,妈的西红柿炒鸡蛋20元,米饭两块一碗,这里什么都不种植,物资都是从格尔木或者西宁运输过来的,真他妈贵啊。而且被告知后面一直雨雪,烂泥路泥浆至少一尺深,当即头大了三分。
天气很冷,温度很低。
青藏线游记:D9,格尔木到西大滩-踏上高原的路
出发时间八点半,又早了点。天气阴沉,看样子要下雨,好在我在格尔木买了一套雨衣,估计裤子不会再弄得像上次橡皮山一样湿透了,果然出发不久便下雨了,且路不是太好走,前十几公里都是坑坑洼洼的。风也很大,斜着吹过来,夹着雨点,渗入头盔,湿透了头发。不过骑得倒还顺利,速度一直都不慢,由于路面太湿,被轮子卷起的水甩得全身都是,灌到鞋子里面,开始小脚冰凉。这时雨裤的劣势也体现了出来,不透气,大量汗水憋在里面相当难受。
很多路上的行人和车辆碰到我都大声叫加油,有个车还安装了扩音器喊话:小鬼,坚持!估计是部队里面的人。 我也的确是在咬牙坚持着,并时刻盼望出现一个大下坡。
到纳赤台时骑了92公里,下午一点多,有许多官兵驻扎在这里演习,坦克一排排的在河边开进。我路过的时候冲路边官兵叫了声好帅,丫居然给我回了个没你帅,一行人都哈哈大笑。纳赤台有所谓的昆仑神泉,我看到了,没停,直接呼啸而过,到旁边的饭店吃面去。
七块钱,吃了碗烩面,使劲叫老板多放面,最后差点没吃完。然后开始等木木,到两点多也没看到他来,就先出发了,大雨,后面37公里骑了3小时,到下午5点的时候赶到西大滩。这个时段这个地方,天气真是不怎么样,四处云气蒸腾,随时下雨的样子。找了旅店,小平房,里面有热情的河南大姐,前面有三条大狗镇守,进去就烤火,烤湿透的鞋子。太冷了,估计温度只有4~5度吧,苦等木木的到来。 后来暖和的时候,拿早上剩下的小笼包逗外面的大狗,还真管用,立马就和我亲热得不得了,走过旁边都摇头摆尾,直往身上扑。
西大滩前面的山是玉珠峰,不过这个天气看不到顶,被云雾所遮掩,一道冰川隐约浮现,据说当年北大登山队在这里挂了个队员,缅怀。
19点,木木赶到西大滩,哥们也蛮惨,几乎把所有的衣服都穿到身上,被汗湿透之后没有换的了,我只好打发怜悯或者他兽性大发抢了我的一条保暖秋裤。点了好贵的菜,吃,住,睡。艰苦的生活,一张床一个被而已,后面的发电机还轰隆隆的工作到了晚上十二点。不太敢直接用他们的被子,还好我又睡袋,零度的适宜温度,冻不到我。
青藏线游记D6,7,8:格尔木,sayhello
一路上果然是沙漠戈壁,早就有人叫我们别骑这段路了,不由得暗自庆幸正确的决定。途中还看到三个骑行车友,正在烈日炎炎下不辞辛苦的前进中,致敬。
到格尔木住下,这是个繁华的地方,居然有都市的感觉,这让我感到一丝诧异,看惯了四周的荒漠,突然回到人间还真有点恍惚。在格尔木买了好多药,两人花了近两百块钱,后来证明完全没有必要。
木木的病一直没好,我们决定在格尔木呆两天再走。第二天早上出去吃饭的时候碰到了来自芜湖的一帮车友,年纪四五十,他们有两个是从芜湖直接骑车过来的,已经块一个月了,还有几个从西安过来,汇集到一起继续走青藏的,后来我们有再碰到他们。
两天在格尔木无事,也没有到处看,天气ms一直阴沉沉的,听说山上很冷,于是在格尔木买了保暖内衣。
2008年9月19日星期五
青藏线游记:D5,茶卡到都兰的无人区
刚出门几公里就看到有一个骑摩托的女的躺在公路旁边,鼻子里流出一丝血,几个人围在四周,估计被车撞了,也不知道还是否有命,我骑着车呼啸而过,后来木木赶上来说,那大姐是六点多被撞,已经魂归黄泉了。
接下来果然100多公里的沙漠戈壁,路旁边连个遮挡都没有,人直接暴露在太阳下面,涂防晒油下来一天还是被晒得暴黑。不过路况还好,没有大上坡。中午就是啃点干粮。下午的时候在链条上面涂了点链条油,顶风骑行挂个大盘速度居然飙到了30,自己想想都不可思议,后来和木木说,他也不信,说在路上顶个风都快崩溃了,速度不到20。
一百一十多公里的时候进入小镇德日哈,路旁都是林荫大道,树木郁郁葱葱,给人感觉就像到了江南,让我十分诧异戈壁地带还有这样的镇子。也没有感觉缺水或饿,我先头径直赶到了都兰,一看时间,不到5点,一百三十多公里,倒也蛮轻松,在都兰的路牌下面等木木,快一个小时还没有到,我便先进镇去了。
这是一个高原小镇,规模还可以,我先去邮局取钱,到六点多木木也到了,找招待所,先是住在都兰县政府招待所,100元/标间,后来发现不能洗澡,水压太小放不出水,遂退房,找了另外一个地方。感觉我们住的地方有点贵,但木木生病了,上吐下泻又感冒的,只好如他意。
在招待所碰到了一对开车过来的夫妇,给我们普及了下高原知识,聊到高原反应的可怕,倒是把我和木木吓到了,他们给了我一个单子,包括葡萄糖红景天百服宁丹参滴丸之类的救命药都全了,我们后来有在格尔木买,但大部分没用上,高反远没有那么可怕,他们估计是缺少锻炼,而且开车上去,骤然海拔上升太大,适应不过来,不过也是好心人哈。
在这里吃晚饭,木木上火啥都不想,就要吃稀饭,妈的大高原面食为主的,而且又不是早餐,有鸡毛稀饭吃,果然跑遍了真个小县城都没有找到,最后在小饭馆吃了点盖浇饭。这边蔬菜是贵啊,西红柿鸡蛋汤12,松仁玉米30,我晕了
青藏线游记:D4,翻越橡皮山
买点馍馍和牛肉,和dulai,ecco,小丁分开了,他们环青海湖,我和木木开始走青藏线。这是一个突发的念头,之前我骑行不过一共2k公里,出发前两天才决定走这条路,没什么准备,因此心里很是忐忑不安。
前些天骑行的腿酸感觉还在,但出发得义无反顾。
天气并不好,出来的时候阴沉沉的,好像要下雨,但赶路是第一要务。刚出来起伏路,坡不长,好爬,过了十公里开始下雨,好像也到了橡皮山下面,开始连续上坡,前些天积累的劳累在这时开始发作了,蹬踏时感觉那个无力啊,走一段路便想要休息,但一想到才刚刚开始爬山,咬咬牙便坚持下去。
雨越下越大,整个路面山头都在烟雨朦胧中,四处白茫茫。我和木木开始找地方避雨。但远远看见有牧民的帐篷,到了路边会发现根本过不去,国家为了保护草原在路旁设置了铁丝网,而且看着帐篷就在不远处,事实很可能会有好几公里,只好继续爬山。
盘山路,坡度大,一路崩溃,我数次想到这过山之后一定要搭车,木木便开始骂我没志气,一点困难就倒,且带以无限bs,现在想起来,木木比我有毅力啊,不过无论如何被bs,我还是骑在他前面,哈哈。在这条约20公里的上山路上,我休息不知多少次,下来啃馍和牛肉,木木当然有红牛了,我很少喝那东西。停下来的时候不敢动,一活动身上汗湿的衣服在肉上摩擦,奇寒无比,不动的话就是温度有点低,忍忍还能过去。
然而骑骑着不知怎么便到山顶了,一看码表,才22km,时间11点半,翻山有两个半小时,速度算是很慢了,橡皮山海拔3817m,由于下雨,被浓雾覆盖,能见度很低。见没有高原反应,我和木木便沾沾自喜起来,以为后面会很轻松。
之后是大下坡,顺着风我们有30多公里以40的速度冲过,爽啊,一点都不用踩,一扫上午的疲惫,接下来剩余约30多公里也是平路,腿还是有累的感觉,不过好歹在3点赶到了茶卡。
找好旅馆,先吃饭,木木居然要吃猪头肉,我算是服他了,在南京什么地方吃不到,偏要跑到这个牛羊肉为主的地区吃,点了一斤,结果没吃完。
之后四公里到茶卡盐场,发现居然要门票20,算了,不进去,好好等待明天。
2008年9月18日星期四
青藏线游记:D3,愉悦的青海湖边旅途
还是我和ecco在前面,到了青海湖边上,开始走走停停拍照。的确在内地看不到这么纯净的颜色,青海湖像一块温润无暇的玉石一般就在身旁,湖边大片大片金黄的油菜花让人赏心悦目。骑在车上,想唱那首走四方么,那就唱吧。一路上游人颇多,于是有的油菜地都被踩出了一条条道道。到青海湖旁边要给湖边的牧民过路费,我也没去。还有很多牧民小孩,打扮得特有民族特色,就想让你拍照,然后他们要钱。我和ecco拍了几张,几个小孩围着要钱,ecco被迫给了十块,他们要我五块,当时我只有四块零钱,那群小孩死活不同意,最终还是拿了我一包榨菜了事。额,对这些在商业区的小孩真的没有一点好感了。
在一路上碰到了好多骑行的车友,有男有女,拉成一条长长的阵线,追上去一问,都是来自宁夏的俱乐部,牵头部队是一群老将,都是公路车,速度不慢。这时我的车变速出了小问题,大盘挂上去便与前拨撞击咔咔作响,于是我也慢慢的落在他们后面。但半路上还是赶上了xiaoding,说好到黑马河集合。
一路无事,看着草原,青海湖,牦牛和油菜花,下午五点半到黑马河,宁夏的车友夸说体力不错,我也只好傻傻的笑。全程120km,住在海盛招待所,目的是为了洗澡。但到浴室发现淋浴的水是用滴的,一点点下来小得很,洗个澡却冻得慌,遂随便擦擦出来了。
大约有一个小时,后面的人都赶上来,总算出来的人又凑到了一起。今天居然过去了四拨车队,有成都的,我们南京的,宁夏的,还有一拨坐车去鸟岛玩,不知道是哪里的,看来这个季节骑车的人是多啊。
明天就是和ecco众人分开,我还颇为忐忑不安,青藏线的挑战是一个不知深浅的泥潭,该去么?
晚上和ecco一席长谈,在他的鼓动下还是决定上路了。
青藏线游记:D2,几欲崩溃的日月山爬坡
出了西宁后,我和ecco在前面,我两速度比他们四块,边骑边等。ecco对他的公路车真是爱护有加,有点烂路便下来推着,曰为了保护车子。后来ecco看到高速,商量着咱走高速吧,109这破路走不了了,等到大伙一起过来商量,还是没有上高速,我却不知如何把ecco甩开了。到了不知名某地,等到一起,我又冲出去好远,突然接到短信说回来吃西瓜。
他们居然在吃西瓜,这还得了,立马回头以四十的速度冲过去,几个人一下干掉硕大一个瓜。木木还说谁给发的短信,于是我暴扁之。
到湟源之前都是山间行走小上坡,我还是一个人在前面,在湟源等他们约半小时,接到短信说在路上吃中饭了,我日,只好吃自己带的大饼和牛肉。等到木木过来,ecco已经乘我上厕所时先跑过去了,我走走停停,顺便照顾下后面的xiaoding和姑娘,他两一个新手,一个没骑过,在后面慢慢悠悠的晃,到岔路口我等半天发现还没上来,回头找过去发现居然停路边上,在看着自行车发呆。
xiaoding说我丫怎么回事居然连她都骑不过了,检查自行车一看刹车片一直在摩擦后面轮胎,啥时候这样的不知道反正搞半天发现不太好搞定。 xiaoding说你先走我到旁边的修车店把这玩意取下来。这时候都有5点多,我想是该赶紧赶路了,还有50多公里。于是对他两说不行就搭车啊我先走。
这是214高速,和109合在一块了,所以自行车也可以上。超过木木和dulai,一路上坡,感觉挺耗体力的。又不知多久到一个收费站,被告知离倒淌河还有25km,继续赶路,并和xiaoding保持联系,他家那位姑娘不行了,据说要在路边住下,这样也好。再一会便看到了在休息的ecco,丫面带笑容说在旁边的沟渠里面大便了一泡,并看着大卡车在头顶呼啸而过。我居然下意思的探过头去瞅了眼,还tm在冒热气,恶心死我了。借此话题两人开始在路旁打闹。
好漂亮的风景阿,抬头是触手可即的白云蓝天,路旁是缤纷的草原,远方是被夕阳染成金黄的群山,斑斓的色彩顿时晕眩了我的身体。我和ecco在这里互相拍照,可惜的是时间已晚,有点暗,我手持又只是一小破数码。不一会木木也赶了上来,开始脱衣服,我有一张感觉不错的丫上半身裸体照就是这里照的。
渐渐的天黑了,我们也没有等到dulai,还得继续赶路。到山上可以走绕过山头的高速也可以走老路爬上山看看日月亭,我们走的是要爬5公里大上坡的老路,累啊,挂个小盘大飞有一下没有一下的往前踩,木木都开始服用红牛兴奋剂了。估计这5公里走走停停有1个多小时吧,温度开始下降,有点冷。在半山腰木木有和一个藏族小姑娘拍照,还说要寄给她,这便是木木,和任何人都能处的相当温和友好,不过那小姑娘却张口要手套手表的,把我们当运货车了吧。最后爬到山顶,木木干掉了三罐红牛。
下山风大气温低,大伙都换上了冲锋衣,此时天完全黑了,只能依稀看到路面,我有个后灯木木有个前灯,但基本等于没用,所以速度不敢太快,好在不用蹬踏用力了,借着隐隐的路面反光还能走。路上收到dulai的短信,他到收费站就已经崩溃,看到大货车停在旁边修理,上去吹吹牛聊聊天就搭上去了,车绑在货车后面,比我们先到倒淌河。运气还算不错,一般招手货车是不会停下的。
一路下坡冲到倒淌河已经九点半,先找了点吃的,在旅店等到dulai,告诉我们xiaoding没有找到住的地方,也没有搭到车,两人还在赶路呢,小丁用长裤系着他女友的小鸟,硬生生拉了有十多公里,天下第一好男人阿,他们要白头偕老了。后来又联系上,他们也在收费站处拦到车,100元要直接坐到青海湖去,就不和我们一起走了。再后来联系到他们的时候已经在青海湖边上,估计是到的是151吧,100/人的房间,据说没有水,没有厕所,被子是发霉的,倒霉到家了。
吃晚饭,到所谓的倒淌河宾馆住下,8元/人,第一天就住到了整个旅行中最便宜的房子。旁边住的还有很多藏族,还有喇嘛,倒是挺心惊肉跳的。好累,腿很酸痛,我开始考虑着明天是不是行程减半。
青藏线游记:D1,塔尔寺
青海湖环湖赛刚刚结束,整个城市干干净净,看不出来有些许自行车的味道。
住在南川西路的雪域高原旅行社,30的四人间,还不错,后来再住到其他的驴友旅社,发现这种旅店都很有特色,角落里尽是民族风情,墙壁上有四方驴友的慷慨流言,好客的店家可以提供详尽的旅游资料。按照计划,我们先去塔尔寺看看,但拖拖拉拉搞到十一点多才出发,一行先到西宁的王国章车行保养下车子,木木去车站发我和他的装车包到拉萨,后又忙忙碌碌吃饭,直到两点多,一行人才正式往塔尔寺赶。
我们有六人,我,ecco,木木,dulai,xiaoding和他的女友,这是个从没有骑行经验的小姑娘。
我和ecco速度匹配,一直骑在前面,上坡又顶风,慢慢地把他们甩开了,ecco骑他那辆3万多的公路车甩开我也很远,到后来他休息,我和dulai先后赶上。
但等很久也不见后三人,短信一问,原来姑娘的小鸟折叠车爆胎了,在旅社修。我们便先走,有点下雨,也不知他们能否赶上过来。
雨是越来越大,好在路不远,25公里,到了塔尔寺一问,80门票,一本地人说给我们60,包导游带我们进去,但我穷学生不想去,ecco和dulai ms也没什么兴趣,便在外面乱转。一会便听说五点关门不要票了。所谓关门其实是导游下班,寺庙不让进,大门虽有锁但门缝很大随便进去。2块钱让老大爷帮忙看车我和dulai进去了。ecco居然不进去,不知为啥,心疼自己的公里车?
反正没导游,我和dulai在里面乱转,也看不懂,胡乱拍照,看到金顶偷偷的思量怎么去敲块金子下来,那真是金做的,我下来问了当地人的,除非那人看似忠厚实则奸诈的忽悠我。在山上,看四周的云和天,好白,好蓝,好清澈,人都有点飘飘然的感觉。好久过去,便下来了。
出来便看到木木和xiaoding在广场上和ecco颇happy的在聊天,姑娘没有过来,估计车不好使,既然还有时间,他们也进去看看。
这一去便是好久,我和dulai等得心烦,冲到里面去等,等一会ecco下来了,却又看到一帮子单反,20个人有吧,每人手里一个长焦,哗哗的闪光四溅。居然找上了我们,说看我们看着像学生想给我们拍照记录学生暑假出来自己骑车旅游生活之类云云,反正免费照相,我们也没反对,便按他们的要求摆弄。把装备搞好,排个队形一起慢慢表演。还要面求微笑。当时我就想,tnnd咱这趟出来估计是搞死搞残,不知道还能微笑几回,这个感觉好像不太对。后来又按他们要求摆了n多造型。其中一个连拍的机器,我骑过去的时候哗哗哗的转一圈几十或十几张相片的拍,着实吓了我一跳。不过被一大堆人拍照的感觉还不错,有点明星的感觉,闪光灯四起,哈。
一会木木和xiaoding也出来,拖着又拍了几张相,时间不早,就返程了,一路下坡顺风,踩得飞快,到旅店看,小鸟爆胎在家,还没有修理呢,晚上搞定之。
在西宁的莫家街夜市腐败,哇,美味的烤羊肉,现在想起来还口水哗哗的。
睡下,明天到倒淌河。
2008年9月13日星期六
perlnotes:一些关于perl语言中执行的知识
use = BEGIN{
require
import
}
begin在编译时进行
如果要手工包含程序路径
BEGIN{
unshift(@INC,"../inclued)";
}
use Foo; #将在include中查找foo
另外一种简单的方法是个use lib qw(../included)
2008年9月11日星期四
perlnotes:闭包
sub generate_greeting{
my $greeting = $_[0];
return sub{
my $project = $_[0];
say "$greeting $project";
}
}
my $rs = generate_greeting("hello");
my $rs1 = generate_greeting("Good");
&$rs("world");
&$rs1("monring");
所有的技巧都在于$greeting已经超出了它的生存期
闭包的内幕
一个变量的创建有两个部分,变量名和变量值,它们之间是分离的实体,通过一个关系链接起来.同时还有一个引用计数记录了指向这个值的引用个数.当引用计数为零时变量值被释放.一个code快里面的变量,在code结束时变量会被释放.
但在这里返回code里面还有这个值,引用计数加一,所以不会被释放.
perlnotes:函数的引用
say "Hello world";
}
my $rs = \&greet;
而不是 $rs = \&greet();
下面语句代表的意思是调用函数greet并创建一个返回值的引用
使用&来调用这个函数
&$rs();
或则 $rs->();
在关闭符号引用的情况下还可以如此
$rs = "greet";
&$rs();
perlnotes: typeglob
*a = *b
此时符号表中的两个表项a和b指向同一个typeglob
改变b的值也会改变a的值
$a=5
$b=10
say $b; ## get 10 here
显然typeglob和词法变量没有任何关系
my *typeglob是错误的
2008年9月10日星期三
perlnotes: 词法变量my和local以及一些生存期的问题
first(); ##get 10 here
sub first{
my $x =11;
second();
}
sub second{
print $x;
}
显然用my没有能够动态的获得一个值,在这里把my 改成local就可以得到11
my和local的重要区别在于my建立真正的新的私有变量
而local的机制是先将原来的全局变量保存,在代码结束的地方在回复到原来值
一般来说用my总是好于用local
但local的一个重要作用是局部化perl的内建变量如@ARGV,$/等
perlnotes: 正则中的/e和/ee
//e = eval "code" 会对code进行插值
my $str = 'My name is $name' ##$name="foo" and you want to substitute $name by foo
$str =~ s/(\$\w)+/\1/gee \1获得$name, /ee对$name插值获得foo
perlnotes: 引用和引用中的->
$array = \@array;
$scalar = $array->[1];
但要注意的是并没有
@slice = $array->[0..2]这种写法,范围操作符在这种情况下并不适用
同样
@slice = $array->[0,2]也不会正常工作,就像上一个note一样,0,2在scalar下会返回2,@slice获得的是$array->[2]
在两个下标之间的->可以省略
比如$sue{child}->{brother}->[0]完全可以写成$sue{child}{brother}{0}
不能省略的情况
$ref=['foo','bar'];
print $ref[0] ##error
print $ref->[0];
print $$ref[0]; #both ok
***********华丽的提示符**********
my @array.....
my $ref=\$array[1];
pop @array
print $ref ##在这里仍然获得$array[1]的值
2008年8月28日星期四
POE 的job_server
后来cu的flw告诉说POE的job_server更为简单明了,于是看了看,简单的翻译了一下
一个简单的任务管理器,他允许多个客户端在服务器上同时运行任务,客户端的输入被送到服务端运行。
#!/usr/bin/perl
# http://poe.perl.org/?POE_Cookbook/Job_Server
use warnings;
use strict;
# Include POE, POE::Component::Server::TCP, and POE::Wheel::Run.
#从POE load如下对象
use POE qw(Component::Server::TCP Wheel::Run);
# The programs that are allowed to run, with their names.
# 下面这些是允许发送运行的程序
my %programs = (
time => "/bin/date",
uptime => "/usr/bin/uptime",
ls => "/bin/ls /var/games/*",
echo => "/bin/cat -",
);
# Start a TCP server. The client will be presented with a list of
# valid commands. They can enter one command: that will execute, and
# its output will be sent back to the client. Then the server will
# close the connection.
# 打开一个tcp服务。客户端会看到一系列命令提示,此时键入一个命令,服务器便会执行
#这个命令,并将输出返回给客户端,之后服务器关闭连接。
POE::Component::Server::TCP->new(
Alias => "job_server",
Port => 32080,
# Send the client a list of available commands when it connects.
# 连接时给客户端发送可用命令列表,这些状态都是内置的,我们可以状态设定回调函数
ClientConnected => sub {
$_[KERNEL]->yield("usage");
# yield函数在POE中使用在当前session唤起一个操作时,如果要将一个操作传递到令一个session,使用post
},
# Make sure the job is destroyed when the client exits.
# 确保客户退出时销毁任务
ClientDisconnected => sub {
delete $_[HEAP]->{job};
},
# Process client input. When no job is running, accept input and
# try to spawn a new one. While a job is running, however, pass
# the client's input to it.
#处理客户端的输入。当服务端没有运行任何任务时,客户端接收命令输入并产生一个新的任务,当有任务运行时,把客户端的输入传递过去。
ClientInput => sub {
my ( $heap, $input ) = @_[ HEAP, ARG0 ];
#POE为内置了一系列参数,如:@_[KERNEL,HEAP,ARGO..$#,SESSION]
#heap是用来存储一个session私有数据的地方
if ( $heap->{job} ) {
$heap->{job}->put($input);
return;
}
my $program = $programs{$input};
unless ( defined $program ) {
$_[KERNEL]->yield("usage");
return;
}
$heap->{job} = POE::Wheel::Run->new(
Program => $program,
StdioFilter => POE::Filter::Line->new(),
StderrFilter => POE::Filter::Line->new(),
StdoutEvent => "got_job_stdout",
StderrEvent => "got_job_stderr",
CloseEvent => "got_job_close",
);
$heap->{client}->put( "Job " . $heap->{job}->PID . " started." );
},
# Inline states are custom event handlers. These add handlers for
# job output, job status, and a convenient usage message.
# Inline状态是定制的事件处理器。在这里添加了任务输出,任务状态和方便的使用说明
InlineStates => {
got_job_stdout => sub {
$_[HEAP]->{client}->put("out: $_[ARG0]");
},
got_job_stderr => sub {
$_[HEAP]->{client}->put("ERR: $_[ARG0]");
},
got_job_close => sub {
my ( $kernel, $heap ) = @_[ KERNEL, HEAP ];
my $job = delete $heap->{job};
$heap->{client}->put( "Job " . $job->PID . " stopped." );
},
usage => sub {
my @commands = sort keys %programs;
$_[HEAP]->{client}->put("Commands: @commands");
},
},
);
# Run the server until it's done.
$poe_kernel->run();
2008年8月22日星期五
2008年8月15日星期五
system中的命令执行顺序
但使用
system 'wget arg';
system 'wget arg1';
发现如果wget后台了,system不会等到wget完事之后再执行第二个
可以 system("comand1;command2"),将顺序执行的任务交给shell去做
2008年6月30日星期一
去掉将数组中的重复项
eg: my @uniq = keys %{{ map { $_ => 1 } @list }};
or
my %seen;
my @uniqed = grep !$seen{$_}++, @list;
显然这里有些值得注意的细节:
1,undef值被++操作符运算时自动处于数值环境而变成零
2,虽然map返回的是一个hash,但不能传递给keys作为参数
我发现第二个错了
map返回的不是hash
虽然在perldoc -f map里面有 %hash = map {get_key_for_hash($_)=> $_} @array
但这里的hash环境还是由%hash提供而不是map搞出来的
2008年6月24日星期二
POE翻译(From Advanced Perl Porgramming)
曾经使用过如TK或GTK进行图形话编程的人都知道此时与一般情况下的编程有点不同。平时我们编程是给程序一堆事件序列并让它帮我们完成。但GUI编程不这样做,而是建立一个对特定事件响应的环境(比如一个窗口)。这就是所谓的事件驱动机制(event-driven paradigm)。
并不是只有GUI程序是这样。例如网络服务器也不是一个事件序列,而是等待连接状态直到根据读入客户端输入处理相关情况,之后又回到等待下一个连接的状态。
类似的我们也可以写个程序监视文件夹,它就像坐在闹钟旁边一样周期性的查看路径里面的文件,检查到了对文件的改动时它可以触发相应的响应。
事件驱动机制的核心是事件循环(event loop),有时也被成为主循环。Tk,事件模块,事件驱动环境如POE都有这个。POE核心/内核(kernel)处理POE的主循环
如上所述,POE可以看作一个微型操作系统,所以叫它内核一点也不过分。当操作系统内核完成环境的构建工作后它便停下等待事件到来,比如从用户来的系统调用或其他硬件中断等。除了为各种事件提供服务外它还需要在各组份间传递信息-这通常就是指进程间通信(IPC)。
POE内核也进行事件服务和处理POE环境下各个部分间的通信,这些进程被叫做session。
2008年6月22日星期日
perl buzz(zz from newsmth)
我写了个详细一些的解答,肯定有不足之处,大家共同讨论吧
1. What does this do?
$foo = $foo[1]
将数组 @foo 的第2个元素赋给标量 $foo
2. What does this print?
@a = ();
$h{'a'} = 'b';
push @a, %h;
print "@a";
push 的参数除了第 1 个以外都处于列表环境当中,而散列在列表环境中会将其中每
个键值对拆开,组合成一个大列表。因此
push @a, %h;
就相当于
push @a, 'a', 'b';
最后经过内插以后的输出结果就是
a b
需要注意的是散列转化为列表时,每个键值对的位置是不固定的,这里只有一个键值
对看不出来。如果散列变成
%h = ('a' => 'b', 'c' => 'd');
那么“@a = %h”的结果可能是以下两种中的某一个
@a = ('a', 'b', 'c', 'd');
@a = ('c', 'd', 'a', 'b');
3. In this code
@x = ('a', 'b', 'c');
$y = scalar ('a', 'b', 'c');
$z = scalar @x;
what are $y and $z set to?
“('a', 'b', 'c')”是列表,“@x”是数组,二者在标量环境下求值的结果是不同
的:列表在标量环境下求值得到的是最后一个元素,数组在标量环境下求值则得到数组本身
的长度。因此上面 $y 赋值得到 'c',而 $z 赋值得到 3。在赋值操作中,赋值号右边内容
所处的环境完全由赋值号左边的内容决定,如果赋值号左边是数组、散列或列表,则右边就
处于列表环境中,若左边是标量则右边也处于标量环境中。这里两个赋值操作的左边都是标
量,因此右边的 scalar 操作实际上没有必要,去掉该操作以后结果不会改变。
4. What does this do?
$c = 'foo';
$a = "$c=\'\\\'\n";
$b = '$c=\'\\\'\n';
双引号中的所有转义序列都有效,且变量会进行内插;单引号中的有效转义序列仅有
“\'”和“\\”,不进行内插操作。如此结论就很明显了。
5. What does this do?
while (
chomp;
unless ($_) {
print "empty line\n";
}
}
Perl 中在布尔环境下求值为假的量只有未定义值 undef、空字符串 ''、数值 0 和
字符串 '0' 这几个,其余的量在布尔环境中都是真值,因此这里的 unless 语句不只挑出
了所有空行,还把只含有一个字符 0 的行也挑出来了,达不到原来的目的。
6. Characterize the possible outcomes of this code
@s = sort foo (1, 4, 3, 2);
assuming that foo is a user-defined subroutine.
题目原来想表现的问题是自定义比较函数返回结果不一致的时候 (比如头一次结果
1 大于 2,下一次结果变成 1 小于 2,这就是比较结果不一致),sort 可能会出错乃至崩
溃。所幸的是这个问题只在 Perl 5.004之前的版本有,后来版本的 sort 对这个情况已经
不敏感了 (不敏感的意思就是在这种情况下排序的结果不一定对,但是肯定不会出错)。其
实函数 foo 的定义方式也值得说明一下,当自定义比较函数没有函数原型时,sort 向比较
函数传递参数是通过和函数处于同一名字空间的全局变量 $a 和 $b 进行的;而当函数具有
$$ 这样的原型时,sort 通过比较函数的参数数组 @_ 传递参数,需要注意的是原型只要
不是 $$,就会按照没有函数原型的情况传递参数。用有原型的比较函数排序一般会比没有
原型的时候慢一些。此外,解释器对 sort 的语法解析太要命:
sort func (1,2,3,4); # 对列表 1,2,3,4 使用比较函数 func 进行排序
sort func 1,2,3,4; # 和上面一样,很正常
sort func(1,2,3,4); # 和上面一样!!
sort (func 1,2,3,4); # 和上面一样!!
sort (func (1,2,3,4)); # 和上面一样!!
sort (func(1,2,3,4)); # 对 func(1,2,3,4) 返回的列表进行默认排序!!
sort ((func(1,2,3,4))); # 和上面一样,很正常
sort ((func (1,2,3,4)));# 语法错误!!
func 有没有原型似乎不会影响对 sort 参数的解释,也就是说就算你事先定义过
sub func($$$$) 或者 sub func(@),也绝对不会改变上面列出来的结果。因此为了尽量少
给自己找麻烦,大家最好还是用尽简单的 sort 形式,千万别在没把握的情况下随意把多行
代码合并到 sort 参数里去。
7. What does this do?
$[ = 42;
唔,没什么好说的,查 perldoc perlvar
8. What does this do?
$x = (sort => (4,8,6));
$y = sort => (4,8,6) ;
“=>”和逗号等价,只是编译时会把它左边的参数当作字符串处理。换个马甲改变不
了本质,它的优先级和逗号一样低。因此题目中的代码相当于以下形式:
$x = ("sort", 4, 8, 6);
($y = "sort"), 4, 8, 6;
前一个语句把列表赋给标量,标量得到的是列表的最后一个元素,因此 $x = 6;后
一个语句把字符串赋给标量,然后赋值结果也就是字符串“sort”和剩余的值组成一个列表
,在空环境中被丢弃,最后 $y = "sort"。
9. What does this do?
print (1+2)+3;
print +(1+2)+3;
经典问题,在 Perl 中看起来“像”函数调用的语句就被处理成函数调用,给上面两
行加上括号:
(print (1+2))+3;
print (+(1+2)+3);
结果就很清楚了,最后输出“36”。
10. What does this do?
$mt = stat($file)[8];
assuming that $file is a valid file handle?
$file 再有效也改变不了语法错误的命运,列表环境的括号不能省,应该改成
(stat($file))[8]。
11. What will this Perl regular expression match?
/$foo[bar]/
Characterize all of the possibilities.
这是典型的变量内插产生二义性的例子,题目中的表达式可以被解释为 ${foo}[bar]
或者 ${foo[bar]},即解释为标量 $foo 的内插或者数组元素 $foo[bar] 的内插,但明显
后一种在这里解释不通,因为字符串“bar”并不能作为数组的下标,所以 Perl 只有使用
前一种解释。但当“[]”中的字符串看起来像常数、变量或者内置关键字的时候就是另一回
事了,如:
/$foo[length]/ 解释为/${foo[length($_)]}/
/$foo[01]/ 解释为/${foo[1]}/
/$foo[$x]/ 解释为/${foo[$x]}/
而且即使被解释为下标的变量不存在,正则表达式引擎仍然会尝试访问,这样在打开
strict 的时候会产生变量未声明的错误。为了避免不必要的歧义,使用正则表达式的时候
最好不要把内插变量放在字符集合之前。
12. Given this subroutine
sub somefunc {
keys %somehash, 0;
}
and assuming that %somehash is defined, what is the value of somefunc()?
Perl 里的函数返回值所处的环境是和调用函数时的环境一样的,因此如果调用形式
是
@array = somefunc;
那么“keys %somehash, 0”就处于列表环境之中,会把 %somehash 的所有键和 0
组成一个列表返回。然而调用形式如果是
$var = somefunc;
它们所处的环境就相应地变成标量环境,而将生成的列表强制转变为标量,也就是返
回列表的最后一个值“0”。
13. What does this do?
$SIG{PIPE} = handler;
别忘了函数引用是 \&func 而不是直接用 func,题目中的那个语句是先调用函数
handler,再将其返回值赋给 $SIG{PIPE},这和预期的修改自定义信号处理函数这一功能可
是差了十万八千里 (当然,如果你说 handler 本来就要返回一个函数引用,这个语句大概
就没什么问题了)。
14. How might this expression be evaluated?
x +2
Enumerate all of the possibilities.
该表达式如何求值主要看 x 是否定义为函数以及函数是否存在原型。求值的结果可
能是:
"x"+2 没有任何关于 x 的定义,因此将其视为裸字,转换为字符串 (前提是没
有打开 strict) 参与计算,最终得到数值 2。
x(+2) x 定义为没有原型的函数,产生函数调用。
x(+2) x 定义为带有 $、@、% 或者其他接受列表参数原型的函数,产生函数调
用。
x()+2 x 定义为带有空原型的函数,产生无参数函数调用并将结果同 2 进行计
算。
x 定义为具有其他原型的函数时,将由于参数和原型不匹配而产生语法错
误。
15. What does this do?
@foo[1] =
只要变量前面的符号是 @,那就意味着产生了一个数组,即使下标只有一个也一样。
给数组赋值时会形成列表环境,而文件读取操作符 <> 在列表环境中的行为是按行读入所有
文件内容,每行形成一个列表元素。这一列表赋给数组切片 @foo[1] 时,只有列表的第一
个元素赋给了 $foo[1],列表的其他内容都被丢弃。因此整个语句的作用就是读入文件所有
内容,将第一行赋给数组 @foo 的第二个元素。
16. What does this do?
$i = 0;
do {
$done = foo();
if ($done) { last; }
$i++;
print "x";
} while ($i < 10);
“do {}”只是一条语句,而不是块,因此不能在其中使用循环控制语句 redo、
next、last 等,但只有在确实执行到这些语句时出问题。比如题目中的程序在 $done 为真
的情况下才会出错。要想在“do {}”结构中使用循环控制,必须用大括号人为制造块,比
如如果想使用 last 控制语句,就需要写成:
{
do {
...
last;
} while (...);
}
而要使用 next 时,要写成:
do {{
...
next;
}} while (...);
这些都是由循环控制语句的特性决定的,可以根据具体情况和需求自行创造符合要求
的格式。
17. Explain when each of ``exists'' or ``defined'' will be printed.
print "exists" if exists $foo{$bar};
print "defined" if defined $foo{$bar};
exists 在给定参数的存储空间已分配时返回真,它不在意这块空间中究竟存放了什
么值;defined 只有在给定参数求值不为 undef 时才返回真,对未分配空间 defined 返回
假,因为对它求值时得到的将是 undef。因此要打印“exists”,必须保证 $foo{$bar} 已
经被赋过值;要打印“defined”,必须保证 $foo{$bar} 被赋过非 undef 的值。还要注意
一点就是,exists 只能对数组或散列的元素使用,而任意表达式都可以作为 defined 的参
数。下面一个例子简单地说明了一下二者的区别:
@a=();
print "1. \$a[0] exists\n" if exists($a[0]); # nothing
print "2. \$a[0] defined\n" if defined($a[0]); # nothing
$a[0]=undef;
print "3. \$a[0] exists\n" if exists($a[0]); # something
print "4. \$a[0] defined\n" if defined($a[0]); # nothing
$a[0]=0;
print "5. \$a[0] exists\n" if exists($a[0]); # something
print "6. \$a[0] defined\n" if defined($a[0]); # something
undef($a[0]);
print "7. \$a[0] exists\n" if exists($a[0]); # something
print "8. \$a[0] defined\n" if defined($a[0]); # nothing
delete($a[0]);
print "9. \$a[0] exists\n" if exists($a[0]); # nothing
print "10. \$a[0] defined\n" if defined($a[0]); # nothing
18. What does this do?
for ($i=0; $i<10; $i++) {
if (
}
if 并没有 while 那样隐含对 $_ 赋值的功能,因此这里的 if 语句从标准输入读入
一行后 print 不会输出任何内容。
19. What does this do?
$f =
这是一个 fileglob,由于是在标量环境下赋值,只会返回首先找到的那个文件名,
而字符集合“[bar]”在匹配时是按顺序调整成“[abr]”进行的,因此查找顺序是“fooa”
、“foob”、“foor”,如果这些文件都不存在则返回未定义值 undef。
20. What does this print?
$_ = "foo bar baz";
--$b{(/(\w+)/)[0]};
--$b{/(\w+)/};
print %b;
“m//”操作符简写为“//”,在没有用“=~”或“!~”将其绑定到字符串上时默认
对“$_”进行操作。没有加“g”修饰符时,在列表环境中它返回捕获内容组成的列表,标
量环境中它返回匹配成功与否 (分别用1和空字符串表示)。题目里第一个自减语句中的正则
表达式处于“(...)[0]”构造的列表环境当中,因此返回捕获内容列表;第二个自减语句处
于标量环境中,返回表示匹配成功的 1。故最终结果相当于:
--$b{foo};
--$b{1};
print %b;
最后输出是“foo-11-1”或“1-1foo-1”。
21. What does this print?
print -0.5 ** -0.5;
Perl 中幂运算“**”的优先级高于单目取反运算符“-”,因此实际解释为:
print -(0.5**(-0.5)); # -1.4142135623731
22. What does this print?
@a = (0 => 0);
print ~$a[0], " ", ~$a[1];
由于使用了“=>”操作符,按照 perldoc perlop 文档中的定义,@a 的第一个元素
本来应该解释为字符串“0”。然而在 5.8.x 的 Perl 中,后面对该元素的取反操作仍然是
按照数值方式进行的,说明“=>”的实际行为和文档中的描述有所差别 (应该属于 bug),
因此要非常小心。不仅仅是 0,所有合法的数值放在“=>”左边时都不会被解释为字符串,
为了以防万一,在你确实需要字符串的地方最好使用引号强迫解释器将其作为字符串看待。
23. What does this print?
$a[0] = 7;
$a[1] = 8;
@b = (5 x @a);
@c = ((5) x @a);
print "@b @c";
“x”算符为右操作数提供了标量环境,而数组 @a 在标量环境中求值就是其长度 2
。当左操作数为标量时“x”的结果是字符串,为列表时结果也是列表。故最终:
@b = ("55");
@c = (5, 5);
显示结果为“55 5 5”。
24. What does this do?
$print_blanks = 1;
while (<>) {
next unless length & $print_blanks;
print;
}
典型问题,length 同单目运算符类似,对参数“获取”能力非常强,未给出参数时
它会尝试将后续表达式结合求值,因此解释为 length(&$print_blanks) ,产生运行时错误
。让 length 使用默认参数 $_ 最好用 length() 的形式。
25. What does this do?
$n = 5;
while (<>) {
if (1 .. $n) { print; }
}
根据 perldoc perlop 中描述的特性,在标量环境中“..”操作符在左操作数为真时
变为真,而在右操作数变为真之后变为假且一直维持该状态。由于题目中 1 和 $n 的值都
是真,因此只有在首次求值时“..”返回真值,后面一直维持假,故只打印出来读入的第一
行内容。
26. What does this do?
$sos = 1_1_1 x x x 1_1_1 ... 1_1_1 x x x 1_1_1;
首先数字之间的下划线可以忽略,其次“x”算符是左结合的,它的右操作数始终被
转换为一个整数,若右操作数小于等于 0 则返回空字符串,因此该语句变成:
$sos = (111 x x) x 111 ... (111 x x) x 111;
裸字“x”被当作字符串看待,随后转换为整数 0,因此“111 x x”就是“111 x 0
”,结果是空字符串。故 ... 算符的两个操作数都是空字符串,因此 $sos 就被赋成空字
符串。
2008年6月21日星期六
network programming start--a udp socket(网络编程初步--一个udp套字连接)
下面是一个建立udp连接的客户端
#!/usr/bin/perl -w use strict; use IO::Socket; my $data; my $port = 2007; my $sock = IO::Socket::INET->new( Proto => 'udp', PeerHost => 'localhost', PeerPort => $port, ) or die "Can not socket: $!\n"; while (<STDIN>) { chomp; $sock->send("$_!") or die "send failed: $!\n"; $sock->recv( $data, 100 ) or die "recv failed: $!\n"; chomp $data; print $data, "\n"; } |
我们使用send来发送信息而使用recv函数来从服务器端读取反馈
在IO::Socket::New中指定了使用udp协议(Proto=>'udp')和服务器的地址(peerhost,peerport)
注意用到一个无限循环,其实完全没必要。
下面是udp服务器代码
1 #!/usr/bin/perl -w 2 3 use strict; 4 use IO::Socket; 5 use constant MAX_LEN => 5000; 6 7 my $port = 2007; 8 my $sock = IO::Socket::INET->new( 9 Proto => 'udp', 10 LocalPort => $port 11 ) or die "can not socket(): $!\n"; 12 print "Servicing incoming request.....\n"; 13 14 my ( $msg_in, $msg_out ); 15 while (1) { 16 next unless $sock->recv( $msg_in, MAX_LEN ); 17 18 # my $peerhost = gethostbyaddr($sock->peeraddr,AF_INET)||$sock->peerhost; 19 # my $peerport = $sock->peerport; 20 21 my $length = length($msg_in); 22 print "Client $peerhost:$peerport says: $msg_in\n"; 23 $msg_out = reverse $msg_in; 24 25 # my $host = sockaddr_in($peerport,inet_aton($peerhost)); 26 # $sock->send($msg_out,0,$host) or die "send failed: $!\n"; 27 28 $sock->send($msg_out) or die "send failed: $!\n"; 29 } 30 $sock->close; |
显然服务器需要绑定的是本机端口(LocalPort).
可以通过多重方法获得远端连接机器信息
send函数可以指定目的地址,此时需要使用sockaddr_in来创建打包格式的地址。
