攻城掠地192dnf鬼泣打团最低配置置 静态配置完成 是什么鬼

推 荐 游 戏
您当前的位置:崩坏31.9鬼铠配置推荐
崩坏31.9版本中鬼铠可以说是进行了史诗性的增强,在新版本中鬼铠需要什么配置?来看看9k9k小编rayxx带来的崩坏31.9鬼铠配置推荐。
队友采用了新角色今样和神恩颂歌,神恩的作用主要是上脆弱和站场,今样主要负责制造击飞。
1.先让神恩在场上散步,出来怪平A蓄力上脆弱,等第二波怪出来时,神恩放大聚怪,蓄力攻击上脆弱,同时展开十字架物理增伤。
2.换卡莲击飞触发鬼铠QTE。
3.切鬼铠出场释放QTE。
如此循环,直到清场。
手游开服表
时间游戏新区开服
手游下载排行榜
大小:82MB
4073次下载
大小:172MB
3922次下载
大小:534MB
3358次下载
大小:115MB
2949次下载
大小:408MB
2648次下载
大小:703MB
2601次下载
大小:320MB
2498次下载
玩家微信公众号
抵制不良游戏 拒绝盗版游戏 注意自我保护 谨防受骗上当 适度游戏益脑 沉迷游戏伤身 合理安排时间 享受健康生活 ——《健康游戏忠告》
增值电信业务:沪B2- 沪ICP备号-2
客服电话:400-021-4006以下为摘录,关于其他,可以看我在这个问题中的回答 &br&&br&&a href=&http://www.zhihu.com/question/& class=&internal&&&span class=&invisible&&http://www.&/span&&span class=&visible&&zhihu.com/question/1980&/span&&span class=&invisible&&9484&/span&&span class=&ellipsis&&&/span&&/a&
&br&&br& css:
&br&&ol&&li& 入门: &i&Head First HTML and CSS, XHTML&/i&
这本2005年底的书依然是最易懂,清晰和正确的入门读物,去看看amazon排名就知道了&/li&&li&全面: &i&CSS, The Definitive Guide (3th Edition) &/i&
Meyer可能是css领域最权威和知名的作者,他在这本书里讲解了每个细节的实现和原理,更详细的东西恐怕只能从w3c那几乎不可读的文档中去寻找了&/li&&li&实践:&i&CSS Mastery (2th Edition)&/i&
Andy budd恐怕是英国最出色的css作者,这本书用简单直接的方式论述了很多实践中组件的正确实现以及可替代方法,包括css3&/li&&li&深入:很遗憾,css在这方面还没有一本必读著作,也可能并不需要,因为到了这个程度,多是用户体验和视觉设计了,目前最接近的是&i& Transcending CSS&/i&, 但不断的技术进化使得书中某些部分感觉有些落伍。&/li&&/ol&&br& 关于css3, 她是一个模块化的渐进式增强,且以2.1为基础,因此,请学好css2再学习css3,这方面我认为只需要一本实践书即可,告诉你css3能做到什么,毕竟,原理是共通的。
&br&&br&&i& The Book of CSS3 &/i& 推荐这本,一个技术人员写的组织清晰的css3模块描述和实践指南,还包括浏览器的实现情况,2011年5月出版,是目前为止最好的。
以下为摘录,关于其他,可以看我在这个问题中的回答
css: 入门: Head First HTML and CSS, XHTML 这本2005年底的书依然是最易懂,清晰和正确的入门读物,去看看amazon排名就知道了全面: CSS, The Definitive Guide (3th Edition)
&a href=&//link.zhihu.com/?target=https%3A//github.com/ricequant/rqalpha& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&ricequant/rqalpha&/a&&br&&figure&&img src=&https://pic4.zhimg.com/v2-5d77e0efbb_b.png& data-rawwidth=&464& data-rawheight=&106& class=&origin_image zh-lightbox-thumb& width=&464& data-original=&https://pic4.zhimg.com/v2-5d77e0efbb_r.png&&&/figure&&br&&br&Ricequant对开放有非常强的意愿,因此我们也一直在研究、讨论和探索如何将开源和线上的云端服务更好的结合,让大家更快、更好的开发出好的策略。&p&我们正式发布了&a href=&//link.zhihu.com/?target=https%3A//github.com/ricequant/rqalpha& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&RQAlpha - 基于纯python量化回测引擎&/a&!&/p&&figure&&img src=&https://pic4.zhimg.com/ac9e7b4a109cef4b21763_b.png& data-rawwidth=&3270& data-rawheight=&1089& class=&origin_image zh-lightbox-thumb& width=&3270& data-original=&https://pic4.zhimg.com/ac9e7b4a109cef4b21763_r.png&&&/figure&&p&
(智能投顾现在这么火,你也可以自己写出自己的智能投顾策略:)&br&&/p&为什么开放?&br&&p&我们相信RQAlpha会和Ricequant很好的一起配合使用。Ricequant提供了一套完整的运行和展示环境,而RQAlpha则可以让你搭建本地运行环境和使用自己的工具链。一起使用RQAlpha和Ricequant会有很多好处。使用RQAlpha可以让你可以有对开发环境有完全的控制权 - 使用你最喜爱的IDE,使用debugger来解决麻烦的bug,用profile来查找性能瓶颈来使策略运行提速。&/p&&p&当你有一个已经开发差不多的不错的策略,你可以复制、黏贴你的策略到Ricequant,我们基本能保证你不需要怎么更改你的策略就可以在Ricequant上运行了,那么可以使用到我们&b&高质量和更齐全的数据&/b&进行回测以及提交到&b&实盘模拟交易&/b&进行实时运行了,还会有实时的交易信号可以发送到你的&b&邮箱和微信&/b&。&/p&&br&如何使用?&p&你可以简单的使用以下命令行安装在自己的本地电脑上:&/p&&br&&div class=&highlight&&&pre&&code class=&language-text&&pip install rqalpha
&/code&&/pre&&/div&&p&当然还有1,2个依赖需要单独安装,请参考我们的github文档:&a href=&//link.zhihu.com/?target=https%3A//github.com/ricequant/rqalpha& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&github.com/ricequant/rq&/span&&span class=&invisible&&alpha&/span&&span class=&ellipsis&&&/span&&/a&&/p&策略运行效果:&figure&&img src=&https://pic2.zhimg.com/991cd6feb068ba4fc24605aaa0306fc5_b.png& data-rawwidth=&1389& data-rawheight=&521& class=&origin_image zh-lightbox-thumb& width=&1389& data-original=&https://pic2.zhimg.com/991cd6feb068ba4fc24605aaa0306fc5_r.png&&&/figure&&br&特色&ul&&li&容易使用:RQAlpha可以让你集中精力在策略的开发上。可以参考./examples 下的范例&/li&&li&需要传入历史数据,计算的结果是pandas的DataFrame, 和PyData的生态系统很好的结合在一起&/li&&li&可以使用Python的统计、机器学习等科学计算库如matplotlib, scipy, statsmodels和sklearn等&/li&&li&免费提供了Ricequant的日级别数据,可以通过互联网自己更新data bundle&/li&&li&很少数的可以做A股回测的开源项目&/li&&/ul&&br&&p&如果您想参与和贡献进来这个项目,可以发邮件给 &a href=&mailto:&&&/a& 联系,或者加入QQ群「」。未来我们会支持更多功能。&/p&
Ricequant对开放有非常强的意愿,因此我们也一直在研究、讨论和探索如何将开源和线上的云端服务更好的结合,让大家更快、更好的开发出好的策略。我们正式发布了! (智能投顾现在这么火,你也可以自己…
作为中国古典文献学专业的学生,此题一定要怒答一记!&br&&br&排名靠前的回答,实际上答的是如何学习“国学”或是“古代文学”,而非如何学习“文言文”。有志于国学的人,当然可以把这些大部头一点点读过去,但如果只是将文言文阅读能力视作一种“技能”,想提升阅读和理解速度的话,以上方法未免有“杀鸡用牛刀”之嫌。我这个方法是&b&专门针对文言文的阅读和理解能力&/b&进行训练的,亲身实践总结,非常有效。&br&&br&先说方法,很简单:&b&翻译&/b&。自己挑一篇古文逐字逐句翻译成白话文。&br&&br&怎么翻?要打好基础,不必贪多,先挑短文,掰开揉碎了来翻。举个栗子:&br&&blockquote&张仆射齐贤体质丰大,饮食过人,尤嗜肥猪肉,每食数斤。天寿院风药黑神丸,常人所服不过一弹丸,公常以五七两为一大剂,夹以胡饼而顿食之。淳化中罢相知安州,安陆山郡,未尝识达官,见公饮?不类常人,举郡惊骇。尝与宾客会食,厨吏置一金漆大桶于厅侧,窥视公所食,如其物投桶中,至暮,酒浆浸渍,涨溢满桶。郡人嗟愕,以谓享富贵者,必有异于人也。&/blockquote&(选自欧阳修《归田录》卷一)&br&&br&先把句子结构理清楚,长句子适当断开以便翻译,倒装的句子理顺,省略的句子成分在括号中补上,专名号比如人名、地名、年号等用下划线标出,(正规的古籍标点,书名要用波浪线标出,不过自学就不必太讲究了。)不熟悉的专有名词可百度之:&br&&blockquote&&u&张&/u&仆射&u&齐贤&/u&体质丰大,饮食过人,尤嗜肥猪肉,每食数斤。&u&天寿院&/u&风药黑神丸,常人所服不过一弹丸,公常以五七两为一大剂,以胡饼夹(之)而顿食之。&u&淳化&/u&中,(公)罢相,知&u&安州&/u&,&u&安陆&/u&(乃)山郡,未尝识达官,见公饮?不类常人,举郡惊骇。(公)尝与宾客会食,厨吏置一金漆大桶于厅侧,窥视公所食,如其物投桶中,至暮,酒浆浸渍,涨溢满桶。郡人嗟愕,以谓享富贵者,必有异于人也。&/blockquote&这一步有多重要呢?再举个栗子:&br&原文:安陆山郡&br&整理:&u&安陆&/u&(乃)山郡&br&如果对地名不熟悉的话,有可能望文生义,把“安陆山郡”认作一个地名。许多专有名词如果不标明,容易与别的句子成分相混淆,导致断错句,会错意。弄清楚安陆是地名后,我们发现这句中仅有两个名词并列。据文意推断,“山郡”实际上是修饰前面的“安陆”,即所谓的“无标志判断句”,直接以名词对名词作出判断。那么,在中间加上一个判断词,翻译起来就通畅多了。&br&&br&第三步就是翻译啦。记住你的目的,不是翻出信达雅的文章,而是通过翻译来熟悉文言句法结构,所以原则就是&b&尽量直译&/b&,把文言和白话一一对应清楚,你所补充的句子成分要标明,哪怕翻出来拗口或者罗嗦一点也没关系:&br&&blockquote&张仆射,名齐贤,(他的)体形庞大,饭量超过常人,尤其嗜好肥猪肉,每次能吃好几斤。天寿院出售的治风邪的药黑神丸,一般人所吃的量不超过一弹丸,张齐贤时常把五七两作为一大剂,用烧饼夹着,一下就吃完了。淳化年间,他(被)罢宰相,到安州做知府,安陆(是)边远山郡,(人们)没有见过大官,看到张齐贤吃喝(饭量)不同于平常人,整个郡(的民众)都十分惊奇骇异。(张齐贤)曾经与宾客聚会宴饮,掌厨的小吏(把)一个涂了金漆的大桶放在大厅一侧,偷偷看张齐贤吃的东西,(就把)同样的食物投入桶里,到了傍晚,酒浆浸渍,(食物)涨满整桶。郡中民众都感叹惊讶,认为能享受富贵的人,一定有不同于常人(之处)。&/blockquote&好吧我自己翻的大概也有不少错误,只是说明一下方法。有误的地方欢迎拍砖。&br&&br&为什么要译得这样精细呢?文言文中绝大多数单字都独立成词,而每个字又有许多义项,我们要弄明白这个字在文中对应的是哪个义项,把它翻译出来,才能更快熟悉多义词的各个义项。比如最后一句中的“郡人嗟愕”,如果偷个懒,把“嗟”字译成“嗟叹”,一般人也都看得懂,不影响理解。但是“嗟”字作动词时,实际上有“叹息”、“感叹”、“赞叹”三个义项,根据文意推敲其情感色彩,翻译成“感叹”,可以更准确地传达文意,而且这样一来,你就对“嗟”的三个义项都熟悉了不是吗~&br&&br&同样的道理,这样翻译也能让你很快熟悉文言文的特殊句法。比如“罢相知安州”五字,整理为“(公)罢相,知&u&安州&/u&”,翻译为“他(被)罢宰相,到安州做知府”。这样一来,你就知道“罢相”实际上应该是被动语态,而“知”字原指官名“知府”,此处是名词活用为动词“做知府”。文言文翻来覆去都是那些句法,亲手翻译几次之后,你遇到这些句式,就能条件反射地脑补出其省略成分和正确顺序,阅读起来自然会迅速许多。&br&&br&辅助翻译的工具书,推荐《古汉语常用字字典》,对于初学者来说够用了。当然也可以利用各种在线字典,挑一个义项最多解释最详细的就好了。&br&&br&那么,要挑什么类型的古文作为题目呢?开头说过,这个方法主要针对文言文阅读理解能力,所以不必去挑战四书五经,诸子百家这些思辨性太强的作品也先放一边。&b&个人建议以笔记类作品起步,而且最好选择“掌故类”笔记,以记录琐事逸闻为主,篇幅短小,语言浅近,用典也不多,内容贴近日常生活,因此非常便于理解。&/b&上文所引《归田录》即是一例,此外还推荐陆游《老学庵笔记》、庄绰《鸡肋编》、周密《癸辛杂识》、沈复《浮生六记》等。&br&这类作品读起来无压力之后,&b&进阶练习可以考虑人物传记,以史书中的“列传”为主&/b&。传记类作品的篇幅长一些,行文风格不如笔记那么轻松随意,不过同样用典不多,内容好理解,故事性强,有助于了解各时代的社会面貌。具体而言,可以挑你感兴趣的,较熟悉的朝代的史书来翻,对于自己了解的内容,翻起来也会顺畅一些。&br&&br&这个方法不以量取胜,不需要你读遍《文选》或者《古文观止》,只要认真对待你翻译的每一篇古文,可以在短时间内看到语感方面的进步。之后,就按着自己的兴趣去读吧。我给出的方法只是训练文言文的语感,但知识体系还是得慢慢建立,没有捷径可走的。共勉。
作为中国古典文献学专业的学生,此题一定要怒答一记! 排名靠前的回答,实际上答的是如何学习“国学”或是“古代文学”,而非如何学习“文言文”。有志于国学的人,当然可以把这些大部头一点点读过去,但如果只是将文言文阅读能力视作一种“技能”,想提升…
&figure&&img src=&https://pic1.zhimg.com/adee891f3d691da47e312_b.jpg& data-rawwidth=&712& data-rawheight=&423& class=&origin_image zh-lightbox-thumb& width=&712& data-original=&https://pic1.zhimg.com/adee891f3d691da47e312_r.jpg&&&/figure&&p&&/p&&h2&&b&金融入门&/b&&/h2&&p&&b&略读40%+泛读30%+精读20%+研读10%&/b&&/p&&h2&&b&Part I 经典著作&/b&&/h2&&p&亚当斯密: 《国富论》&/p&&p&李嘉图:《政治经济学及赋税原理》&/p&&p&马克思: 《资本论》&/p&&p&马歇尔:《经济学原理》&/p&&p&凯恩斯:《就业,利息和货币通论》&/p&&p&萨缪尔森:《经济学》&/p&&h2&&b&Part II 经典教材&/b&&/h2&&p&曼昆:《经济学原理》宏微上下两本 ——入门&/p&&p&高鸿业:《西方经济学》宏观,微观 ——初级&/p&&p&范里安:《微观经济学:现代观点》 ——中级&/p&&p&曼昆:《宏观经济学》
——中级&/p&&p&米什金:《货币金融学》&/p&&p&罗斯:《公司理财》&/p&&p&博迪:《投资学》&/p&&p&法博齐:《金融市场与金融机构基础》&/p&&p&格鲁格曼:《国际经济学》&/p&&p&赫尔:《期权期货及其他衍生品》&/p&&p&舍夫林:《资产定价的行为方法》&/p&&p&赖利:《投资分析与组合管理》&/p&&p&福布斯:《行为金融》&/p&&p&特维德:《金融心理学》&/p&&p&博迪,莫顿:《金融学》&/p&&p&法博兹:《债券市场:分析和策略》&/p&&p&黄达:《金融学》&/p&&p&姜波克:《国际金融学》&/p&&p&张亦春:《金融市场学》&/p&&h2&&b&Part III 经典读物&/b&&/h2&&p&格雷厄姆:《证券分析》&/p&&p&格雷厄姆:《聪明的投资者》&/p&&p&罗伯特清崎:《富爸爸投资指南》&/p&&p&彼得林奇:《战胜华尔街》&/p&&p&江恩:《江恩华尔街45年》&/p&&p&麦基尔:《漫步华尔街》&/p&&p&罗伯特希勒:《非理性繁荣》&/p&&p&吴晓波:《大败局》&/p&&p&吴晓波:《激荡三十年》&/p&&p&宋鸿兵:《货币战争》&/p&&p&陈志武:《金融的逻辑》&/p&&p&渔阳:《乱世华尔街》&/p&&h2&&b&其他拓展&/b&&/h2&&p&《西方经济史》《全球通史》《人类简史》&/p&&p&《管理学》《市场营销》《组织行为学》&/p&&p&《会计学》《税法》《公司法》《保险学》&/p&&p&《概率论与数理统计》《运筹学》&/p&&p&《 Probability and Satistics》 DeGROOT SCHERVISH&/p&&p&《Introduction to Probability Models》 SHELDON M.ROSS&/p&&p&《Introduction to Probability and Mathematical Satistics》Duxbury classic series&/p&&p&注:不深入的读第一本或者第二本就可以了。&/p&&p&Sheldon M.Ross:&stochastic processes&&/p&&p&林元烈:《应用随机过程》 &/p&&p&电影:《华尔街之狼》&/p&&p&&b&数据分析&/b&&/p&&p&Sql Excel Spss Stata Sas Matlab&b&R Python&/b&&/p&&p&Life is short ,I use python:&/p&&p&《利用python进行数据挖掘》《Python for Data analysis》&/p&&p&《数据挖掘导论》&/p&&p&《集体智慧编程》&/p&&p&《机器学习系统设计》&/p&&p&《推荐系统实战》&/p&&p&《machine learning》Stanford&/p&&p&《机器学习实战》&/p&&p&《统计学习方法》&/p&&p&R当然也要学:&/p&&p&《R IN ACTION》《R 语言实战》&/p&&p&SQL:&/p&&p&《Head First SQL》《深入浅出SQL》&/p&&p&编程网站:&/p&&p&&a href=&https://link.zhihu.com/?target=http%3A//www.pythontab.com/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&PythonTab:Python中文开发者社区门户&/a& &/p&&p&&a href=&https://link.zhihu.com/?target=https%3A//www.ilovematlab.cn/forum.php& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&MATLAB中文论坛&/a& &/p&&p&&a href=&https://link.zhihu.com/?target=http%3A//bbs.pinggu.org/forum-68-1.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&SAS_SAS软件_SAS教程&/a& &/p&&p&&a href=&https://link.zhihu.com/?target=http%3A//www.matlabsky.com/forum-47-1.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&SAS & SPSS 论坛|MATLAB技术论坛&/a&&/p&&p&----------------- recommendations----------------&/p&&p&&a href=&https://www.zhihu.com/question//answer/& class=&internal&&非金融专业人士,可以通过什么途径进入金融业?&/a& &/p&&p&&a href=&https://www.zhihu.com/question/& class=&internal&&曼昆经济学读完了,接下来该读什么? &/a& &/p&&p&&a href=&https://www.zhihu.com/question//answer/& class=&internal&&有哪些关于经济或金融的纪录片? &/a& &/p&&p&&a href=&https://www.zhihu.com/question//answer/& class=&internal&&经济学入门必读书籍有哪些值得推荐? &/a& &/p&&p&&a href=&https://www.zhihu.com/question//answer/?from=profile_answer_card& class=&internal&&经济学入门必读书籍有哪些值得推荐? &/a& &/p&&p&&a href=&https://www.zhihu.com/question//answer/& class=&internal&&经济学与金融学相关课程应必备哪些? &/a& &/p&&p&&a href=&https://www.zhihu.com/question//answer/& class=&internal&&有哪些值得推荐的财务报表分析的书,或者学习建议?&/a&&/p&&p&&a href=&https://www.zhihu.com/question//answer/& class=&internal&&有哪些描述投行内幕的书? &/a& &/p&&p&&a href=&https://www.zhihu.com/question//answer/& class=&internal&&有哪些适合普通人阅读的经济学论文? &/a& &/p&&p&&a href=&https://www.zhihu.com/question/& class=&internal&&求一本系统介绍宏观经济学流派和发展的书? &/a& &/p&&p&&a href=&https://www.zhihu.com/question//answer/& class=&internal&&如何学好经济学?&/a&&/p&&p&&b&略读40%+泛读30%+精读20%+研读10%&/b&&/p&&p&&b&多速读,做笔记,勤思考,常复盘。&/b&&/p&&p&&b&随心,随性,随意。&/b&&/p&
金融入门略读40%+泛读30%+精读20%+研读10%Part I 经典著作亚当斯密: 《国富论》李嘉图:《政治经济学及赋税原理》马克思: 《资本论》马歇尔:《经济学原理》凯恩斯:《就业,利息和货币通论》萨缪尔森:《经济学》Part II 经典教材曼昆:《经济学原理》宏…
关于教材方面,我掌握的关于你已经学过的教材文献的信息量并不是很多,所以以下信息仅供参考:&br&&br&微观:&br&初级方面,三本书择一,分别是Samuelson的经济学(目前到第十八版了,国内有影印的可以买),Stiglitz的(目前到第三版,有没有英文影印的不知道),和Mankiw的那本。Samuelson的是老牌了,很详尽全面,而且照顾初学者,比较浅显易懂,当年我是看第12版的英文版入门的,我很喜欢Samuelson的这本。Stiglitz的那个比较偏重信息不对称等内容,毕竟是作者的老本行。Mankiw的这个现在用的很多,我没读过,没法多做判断。&br&初级微观随便翻翻即可,不要花太多时间。&br&&a href=&//link.zhihu.com/?target=http%3A//book.douban.com/subject/1487888/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&经济学.英文版·第18版/中国教育部推荐原版引进教材 (豆瓣)&/a&&br&&a href=&//link.zhihu.com/?target=http%3A//book.douban.com/subject/1410322/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&经济学(上下册)(第三版) (豆瓣)&/a&&br&&a href=&//link.zhihu.com/?target=http%3A//book.douban.com/subject/1856927/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&经济学原理 (豆瓣)&/a&&br&&br&中级方面,这个没得说,必定是Hal Varian的Intermediate Microeconomics,很赞,帮助学生从语言描述的经济学过渡到用数学来说话。建议你现在多花些时间看看这个。另一个备选方案是Nicholson的这本,据说也不错。&br&&a href=&//link.zhihu.com/?target=http%3A//book.douban.com/subject/4285945/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Intermediate Microeconomics (豆瓣)&/a&&br&&a href=&//link.zhihu.com/?target=http%3A//book.douban.com/subject/2267246/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Intermediate Microeconomics (豆瓣)&/a&&br&&br&高级方面,也没得说,一本博大精深的MWG的microeconomic theory,厚,详尽,罗嗦。看完就会忘,但一定要认真读完(尽管会很痛苦,嘿嘿),然后放在案头作手册,读文献的时候遇到想不起来的东西就可以随时查了。这本书是高级微观的高年级本科生和研究生必读。有英文影印的,有兴趣的话,入一本吧。&br&&a href=&//link.zhihu.com/?target=http%3A//book.douban.com/subject/1264648/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&微观经济理论 (豆瓣)&/a&&br&要是翻了MWG觉得太难,不得其门,可以在读完Varian的intermediate MicroE之后,继续看以下1)和2),看完了之后再回过头来翻MWG,就不那么难了&br&1)他的microeconomic analysis,这是中级微观和高级微观之间的过渡教材,写的不错&br&&a href=&//link.zhihu.com/?target=http%3A//book.douban.com/subject/1727803/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Microeconomic Analysis (豆瓣)&/a&&br&2)一本数理经济学的入门教材。这个下面再说。&br&&br&&br&数理经济学:&br&入门级的教材,我觉得最好的是两本,一是Suen and Silberberg的The Structure of Economics,这个要怒赞,结构条理都很清楚,翻一遍下来,用数学的语言掌握经济学就不难了。有影印版。二是蒋中一的数理经济学的基本方法,这个是从英文翻译过来的。原著可能也不会难搞到。&br&&a href=&//link.zhihu.com/?target=http%3A//book.douban.com/subject/1226129/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&经济学的结构 (豆瓣)&/a&&br&&a href=&//link.zhihu.com/?target=http%3A//book.douban.com/subject/1961174/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&数理经济学的基本方法 (豆瓣)&/a&&br&更进阶一些的,就要看比较变态的数学教材了,那套 Springer的UTM系列据说不错,可惜我没看过,惭愧。&br&&br&宏观:&br&Varian的中级微观读过,就可以一边着手看数理经济学和高级微观,一边开始着手看宏观了。&br&入门级的,基本上Mankiw和Samuelson的那个可以覆盖住。老师让我着重看的是Branson的那本,比较老了,80年代的教材,但前五章写的很精彩,看过之后基本上就对凯恩斯主义和新古典主义两条主线有了基本的了解了,方便进入后来的新古典主义综合。&br&&a href=&//link.zhihu.com/?target=http%3A//www.amazon.com/Macroeconomic-Theory-Policy-William-Branson/dp//ref%3Dsr_1_1%3Fie%3DUTF8%26s%3Dbooks%26qid%3D%26sr%3D8-1& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Macroeconomic Theory and Policy (3rd Edition): William H. Branson: 6: Amazon.com: Books&/a&&br&&br&中级的(或者初、中级的),Dornbusch and Fischer的那本不错,也可以看Krugman的。总之如果你前面微观和数理经济学的基础打得扎实的话,直到中级宏观就都不会很难,主要是领会宏观经济学几个主要的概念和方向就行了。&br&&a href=&//link.zhihu.com/?target=http%3A//book.douban.com/subject/2152886/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Macroeconomics (豆瓣)&/a&&br&&a href=&//link.zhihu.com/?target=http%3A//book.douban.com/subject/2252611/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Macroeconomics (豆瓣)&/a&&br&&br&然后建议看一些经济学思想史。我看过的,强烈推荐的是Schumpeter的那个经济分析史,比较老了,但是很酷,当年看它看得很入迷。&br&现代的,讲凯恩斯之后的宏观经济学思想史的,很不错的是这本Modern Macroeconomics,把凯恩斯主义和新古典主义从20年代以来的打打杀杀讲得比较明白了,看过这本书,再翻高级宏观的很多东西,就不难(见附件)&br&&a href=&//link.zhihu.com/?target=http%3A//book.douban.com/subject/1773334/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&History of Economic Analysis (豆瓣)&/a&&br&&br&高级宏观:&br&至少我觉得必看的是Romer的Advanced Macroeconomics,超级喜欢的一本书。&br&Blanchard and Fishcher的一个讲义集子Lectures on MacroE,比他们主要给本科生作教材的那本难度高一些,适合作深入阅读。&br&&a href=&//link.zhihu.com/?target=http%3A//book.douban.com/subject/1480907/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Lectures on Macroeconomics (豆瓣)&/a&&br&&a href=&//link.zhihu.com/?target=http%3A//book.douban.com/subject/1471016/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Advanced Macroeconomics (豆瓣)&/a&&br&Ljungqvist and Sargent的这本Recursive Macroeconomic Theory,怎么强调它的重要性都不过分,现代宏观经济学的很多研究工具和方法,都要靠看它来掌握。有这么个说法,没读过这本Recursive MacroE的,就不叫经济学的研究生。可惜,惭愧,我没有读过这本书,所以后面我读Acemoglu大牛的书的时候无比吃力。想要再回头捡起来的时候,已经没时间了。唉。&br&&a href=&//link.zhihu.com/?target=http%3A//book.douban.com/subject/1441389/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Recursive Macroeconomic Theory (豆瓣)&/a&&br&&br&然后是根据自己的方向去作深入阅读了。比如经济增长理论,比如货币政策,比如public finance,新经济地理,等等。这么多方向,一是我并不很了解,二是大多数都是研究生之后的教材,可能对于现在的你也不是很适用。只就其中的两个领域,经济增长理论和新经济地理推荐叫才给你。&br&&br&经济增长理论:&br&Barro and Sala-i-Martin的economic growth,2004年有第二版了,这个是老牌“圣经”,这个领域的必读,很赞。&br&Acemoglu 的Introduction to Modern Economic Growth。2009年新出的教材,Acemoglu是我最崇拜的大牛之一,他早晚会得Nobel的。别被标题所迷惑了,这本书绝对不是 introduction那么简单。作者很野心,有取Barro and Sala-i-Martin那本书的地位而代之的意思,呵呵。不过写的真的很好。&br&Handbook of Economic Growth。Aghion and Durlauf编出这么个浩浩荡荡的handbook出来,功德无量。(是个论文集子,都可以在elsevier上下下来,不过C. Jones做了个合集的pdf,也可以上他的主页去下载。&br&&a href=&//link.zhihu.com/?target=http%3A//book.douban.com/subject/2017469/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Economic Growth (豆瓣)&/a&&br&&a href=&//link.zhihu.com/?target=http%3A//book.douban.com/subject/3298715/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Introduction to Modern Economic Growth (豆瓣)&/a&&br&&br&&br&新经济地理:&br&Developmen, Geography and Economic Theory, by Krugman。一本小册子,几乎没有数学,非常适合作新经济地理的入门。这个领域现在很热。&br&Spatial Economy,by Fujita, Krugman and Venables。好书,牛书,强烈推荐读这个方向的学生认真去读的。只是数学公式太多了,前面MWG那本和数理的功底没打好,这本书看起来会比较吃力。&br&Fujita and Thisse的The Economics of Agglomeration。这个也很好。&br&(这个领域Krugman, Fujita, Thisse,加上一个Venables。)&br&&a href=&//link.zhihu.com/?target=http%3A//book.douban.com/subject/2017338/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Development, Geography and Economic Theory (豆瓣)&/a&&br&&a href=&//link.zhihu.com/?target=http%3A//book.douban.com/subject/1825742/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&The Spatial Economy (豆瓣)&/a&&br&&a href=&//link.zhihu.com/?target=http%3A//book.douban.com/subject/2017365/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Economics of Agglomeration (豆瓣)&/a&&br&&br&另:制度经济学也挺热的,这些年,也有一份不错的书单。但就不多说了,如果你感兴趣,可以再说。&br&&br&然后就是文献阅读了,这个更因人而异,不多说了。
关于教材方面,我掌握的关于你已经学过的教材文献的信息量并不是很多,所以以下信息仅供参考: 微观: 初级方面,三本书择一,分别是Samuelson的经济学(目前到第十八版了,国内有影印的可以买),Stiglitz的(目前到第三版,有没有英文影印的不知道),和M…
&figure&&img src=&https://pic2.zhimg.com/d68df4eae1e7ab5d2a1cb46_b.jpg& data-rawwidth=&1920& data-rawheight=&960& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&https://pic2.zhimg.com/d68df4eae1e7ab5d2a1cb46_r.jpg&&&/figure&&p&本文是&a href=&https://zhuanlan.zhihu.com/json-tutorial& class=&internal&&《从零开始的 JSON 库教程》&/a&的第一个单元。教程练习源代码位于 &a href=&http://link.zhihu.com/?target=https%3A//github.com/miloyip/json-tutorial& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&json-tutorial&/a&。&br&&/p&&br&&p&本单元内容:&br&&/p&&ol&&li&JSON 是什么&br&&/li&&li&搭建编译环境&br&&/li&&li&头文件与 API 设计&br&&/li&&li&JSON 语法子集&br&&/li&&li&单元测试&br&&/li&&li&宏的编写技巧&br&&/li&&li&实现解析器&br&&/li&&li&关于断言&br&&/li&&li&总结与练习&br&&/li&&li&常见问答&br&&/li&&/ol&&br&&p&(题图 &a href=&http://link.zhihu.com/?target=https%3A//unsplash.com/search/lantern%3Fphoto%3DLkHXBKpwhZ8& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Photo by Gianandrea Villa&/a&)&br&&/p&&h1&1. JSON 是什么&/h1&&p&JSON(JavaScript Object Notation)是一个用于数据交换的文本格式,现时的标准为&a href=&http://link.zhihu.com/?target=http%3A//www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&ECMA-404&/a&。&/p&&p&虽然 JSON 源至于 JavaScript 语言,但它只是一种数据格式,可用于任何编程语言。现时具类似功能的格式有 XML、YAML,当中以 JSON 的语法最为简单。&/p&&p&例如,一个动态网页想从服务器获得数据时,服务器从数据库查找数据,然后把数据转换成 JSON 文本格式:&/p&&br&&div class=&highlight&&&pre&&code class=&language-json&&&span&&/span&&span class=&p&&{&/span&
&span class=&nt&&&title&&/span&&span class=&p&&:&/span& &span class=&s2&&&Design Patterns&&/span&&span class=&p&&,&/span&
&span class=&nt&&&subtitle&&/span&&span class=&p&&:&/span& &span class=&s2&&&Elements of Reusable Object-Oriented Software&&/span&&span class=&p&&,&/span&
&span class=&nt&&&author&&/span&&span class=&p&&:&/span& &span class=&p&&[&/span&
&span class=&s2&&&Erich Gamma&&/span&&span class=&p&&,&/span&
&span class=&s2&&&Richard Helm&&/span&&span class=&p&&,&/span&
&span class=&s2&&&Ralph Johnson&&/span&&span class=&p&&,&/span&
&span class=&s2&&&John Vlissides&&/span&
&span class=&p&&],&/span&
&span class=&nt&&&year&&/span&&span class=&p&&:&/span& &span class=&mi&&2009&/span&&span class=&p&&,&/span&
&span class=&nt&&&weight&&/span&&span class=&p&&:&/span& &span class=&mf&&1.8&/span&&span class=&p&&,&/span&
&span class=&nt&&&hardcover&&/span&&span class=&p&&:&/span& &span class=&kc&&true&/span&&span class=&p&&,&/span&
&span class=&nt&&&publisher&&/span&&span class=&p&&:&/span& &span class=&p&&{&/span&
&span class=&nt&&&Company&&/span&&span class=&p&&:&/span& &span class=&s2&&&Pearson Education&&/span&&span class=&p&&,&/span&
&span class=&nt&&&Country&&/span&&span class=&p&&:&/span& &span class=&s2&&&India&&/span&
&span class=&p&&},&/span&
&span class=&nt&&&website&&/span&&span class=&p&&:&/span& &span class=&kc&&null&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&网页的脚本代码就可以把此 JSON 文本解析为内部的数据结构去使用。&/p&&p&从此例子可看出,JSON 是树状结构,而 JSON 只包含 6 种数据类型:&/p&&ul&&li&null: 表示为 null&/li&&li&boolean: 表示为 true 或 false&/li&&li&number: 一般的浮点数表示方式,在下一单元详细说明&/li&&li&string: 表示为 &...&&/li&&li&array: 表示为 [ ... ]&/li&&li&object: 表示为 { ... }&/li&&/ul&&p&我们要实现的 JSON 库,主要是完成 3 个需求:&/p&&ol&&li&把 JSON 文本解析为一个树状数据结构(parse)。&/li&&li&提供接口访问该数据结构(access)。&/li&&li&把数据结构转换成 JSON 文本(stringify)。&/li&&/ol&&figure&&img src=&http://pic2.zhimg.com/75eecbdd3b028e1479e3d_b.png& data-rawwidth=&440& data-rawheight=&78& class=&origin_image zh-lightbox-thumb& width=&440& data-original=&http://pic2.zhimg.com/75eecbdd3b028e1479e3d_r.png&&&/figure&&p&我们会逐步实现这些需求。在本单元中,我们只实现最简单的 null 和 boolean 解析。&/p&&h1&2. 搭建编译环境&/h1&&p&我们要做的库是跨平台、跨编译器的,同学可使用任意平台进行练习。&/p&&p&练习源代码位于 &a href=&http://link.zhihu.com/?target=https%3A//github.com/miloyip/json-tutorial& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&json-tutorial&/a&,当中 tutorial01 为本单元的练习代码。建议同学登记为 GitHub 用户,把项目 fork 一个自己的版本,然后在上面进行修改。不了解版本管理的同学,也可以按右方「Clone or download」按钮,简单下载一个 zip 文件。&/p&&p&我们的 JSON 库名为 leptjson,代码文件只有 3 个:&/p&&ol&&li&leptjson.h:leptjson 的头文件(header file),含有对外的类型和 API 函数声明。&/li&&li&leptjson.c:leptjson 的实现文件(implementation file),含有内部的类型声明和函数实现。此文件会编译成库。&/li&&li&test.c:我们使用测试驱动开发(test driven development, TDD)。此文件包含测试程序,需要链接 leptjson 库。&/li&&/ol&&p&为了方便跨平台开发,我们会使用一个现时最流行的软件配置工具 &a href=&http://link.zhihu.com/?target=https%3A//cmake.org/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&CMake&/a&。&/p&&p&在 Windows 下,下载安装 CMake 后,可以使用其 cmake-gui 程序:&/p&&figure&&img src=&http://pic1.zhimg.com/21f865a087b7775b8fcc_b.png& data-rawwidth=&663& data-rawheight=&420& class=&origin_image zh-lightbox-thumb& width=&663& data-original=&http://pic1.zhimg.com/21f865a087b7775b8fcc_r.png&&&/figure&&p&先在 &Where is the source code& 选择 json-tutorial/tutorial01,再在 &Where to build the binary& 键入上一个目录加上 /build。&/p&&p&按 Configure,选择编译器,然后按 Generate 便会生成 Visual Studio 的 .sln 和 .vcproj 等文件。注意这个 build 目录都是生成的文件,可以随时删除,也不用上传至仓库。&/p&&p&在 OS X 下,建议安装 &a href=&http://link.zhihu.com/?target=http%3A//brew.sh/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Homebrew&/a&,然后在命令行键入:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&$ brew install cmake
$ &span class=&nb&&cd&/span& github/json-tutorial/tutorial01
$ mkdir build
$ &span class=&nb&&cd&/span& build
$ cmake -DCMAKE_BUILD_TYPE&span class=&o&&=&/span&Debug ..
&/code&&/pre&&/div&&p&这样会使用 GNU make 来生成项目,把 Debug 改成 Release 就会生成 Release 配置的 makefile。&/p&&p&若你喜欢的话,CMake 也可以生成 Xcode 项目:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&$ cmake -G Xcode ..
$ open leptjson_test.xcodeproj
&/code&&/pre&&/div&&p&而在 Ubuntu 下,可使用 apt-get 来安装:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&$ apt-get install cmake
&/code&&/pre&&/div&&p&无论使用什么平台及编译环境,编译运行后会出现:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&$ ./leptjson_test
/Users/miloyip/github/json-tutorial/tutorial01/test.c:56: expect: &span class=&m&&3&/span& actual: 0
11/12 &span class=&o&&(&/span&91.67%&span class=&o&&)&/span& passed
&/code&&/pre&&/div&&p&若看到类似以上的结果,说明已成功搭建编译环境,我们可以去看看那几个代码文件的内容了。&/p&&h1&3. 头文件与 API 设计&/h1&&p&C 语言有头文件的概念,需要使用 #include 去引入头文件中的类型声明和函数声明。但由于头文件也可以 #include 其他头文件,为避免重复声明,通常会利用宏加入 #include 防范(include guard):&/p&&br&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&cp&&#ifndef LEPTJSON_H__&/span&
&span class=&cp&&#define LEPTJSON_H__&/span&
&span class=&cm&&/* ... */&/span&
&span class=&cp&&#endif &/span&&span class=&cm&&/* LEPTJSON_H__ */&/span&&span class=&cp&&&/span&
&/code&&/pre&&/div&&p&宏的名字必须是唯一的,通常习惯以 _&em&H__&/em& 作为后缀。由于 leptjson 只有一个头文件,可以简单命名为 LEPTJSON_H__。如果项目有多个文件或目录结构,可以用 项目名称_目录_文件名称_H__ 这种命名方式。&/p&&p&如前所述,JSON 中有 6 种数据类型,如果把 true 和 false 当作两个类型就是 7 种,我们为此声明一个枚举类型(enumeration type):&/p&&br&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&k&&typedef&/span& &span class=&k&&enum&/span& &span class=&p&&{&/span& &span class=&n&&LEPT_NULL&/span&&span class=&p&&,&/span& &span class=&n&&LEPT_FALSE&/span&&span class=&p&&,&/span& &span class=&n&&LEPT_TRUE&/span&&span class=&p&&,&/span& &span class=&n&&LEPT_NUMBER&/span&&span class=&p&&,&/span& &span class=&n&&LEPT_STRING&/span&&span class=&p&&,&/span& &span class=&n&&LEPT_ARRAY&/span&&span class=&p&&,&/span& &span class=&n&&LEPT_OBJECT&/span& &span class=&p&&}&/span& &span class=&n&&lept_type&/span&&span class=&p&&;&/span&
&/code&&/pre&&/div&&p&因为 C 语言没有 C++ 的命名空间(namespace)功能,一般会使用项目的简写作为标识符的前缀。通常枚举值用全大写(如 LEPT_NULL),而类型及函数则用小写(如 lept_type)。&/p&&p&接下来,我们声明 JSON 的数据结构。JSON 是一个树形结构,我们最终需要实现一个树的数据结构,每个节点使用 lept_value 结构体表示,我们会称它为一个 JSON 值(JSON value)。 在此单元中,我们只需要实现 null, true 和 false 的解析,因此该结构体只需要存储一个 lept_type。之后的单元会逐步加入其他数据。&/p&&br&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&k&&typedef&/span& &span class=&k&&struct&/span& &span class=&p&&{&/span&
&span class=&n&&lept_type&/span& &span class=&n&&type&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&&span class=&n&&lept_value&/span&&span class=&p&&;&/span&
&/code&&/pre&&/div&&p&C 语言的结构体是以 struct X {} 形式声明的,定义变量时也要写成 struct X。为方便使用,上面的代码使用了 typedef。&/p&&p&然后,我们现在只需要两个 API 函数,一个是解析 JSON:&/p&&br&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&kt&&int&/span& &span class=&nf&&lept_parse&/span&&span class=&p&&(&/span&&span class=&n&&lept_value&/span&&span class=&o&&*&/span& &span class=&n&&v&/span&&span class=&p&&,&/span& &span class=&k&&const&/span& &span class=&kt&&char&/span&&span class=&o&&*&/span& &span class=&n&&json&/span&&span class=&p&&);&/span&
&/code&&/pre&&/div&&p&传入的 JSON 文本是一个 C 字符串(空结尾字符串/null-terminated string),由于我们不应该改动这个输入字符串,所以使用 const char* 类型。&/p&&p&另一注意点是,传入的根节点指针 v 是由使用方负责分配的,所以一般用法是:&/p&&br&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&n&&lept_value&/span& &span class=&n&&v&/span&&span class=&p&&;&/span&
&span class=&k&&const&/span& &span class=&kt&&char&/span& &span class=&n&&json&/span&&span class=&p&&[]&/span& &span class=&o&&=&/span& &span class=&p&&...;&/span&
&span class=&kt&&int&/span& &span class=&n&&ret&/span& &span class=&o&&=&/span& &span class=&n&&lept_parse&/span&&span class=&p&&(&/span&&span class=&o&&&&/span&&span class=&n&&v&/span&&span class=&p&&,&/span& &span class=&n&&json&/span&&span class=&p&&);&/span&
&/code&&/pre&&/div&&p&返回值是以下这些枚举值,无错误会返回 LEPT_PARSE_OK,其他值在下节解释。&/p&&br&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&k&&enum&/span& &span class=&p&&{&/span&
&span class=&n&&LEPT_PARSE_OK&/span& &span class=&o&&=&/span& &span class=&mi&&0&/span&&span class=&p&&,&/span&
&span class=&n&&LEPT_PARSE_EXPECT_VALUE&/span&&span class=&p&&,&/span&
&span class=&n&&LEPT_PARSE_INVALID_VALUE&/span&&span class=&p&&,&/span&
&span class=&n&&LEPT_PARSE_ROOT_NOT_SINGULAR&/span&
&span class=&p&&};&/span&
&/code&&/pre&&/div&&p&现时我们只需要一个访问结果的函数,就是获取其类型:&/p&&br&&div class=&highlight&&&pre&&code class=&language-cmake&&&span&&/span&&span class=&err&&lept_type&/span& &span class=&nb&&lept_get_type&/span&&span class=&p&&(&/span&&span class=&s&&const&/span& &span class=&s&&lept_value*&/span& &span class=&s&&v&/span&&span class=&p&&)&/span&&span class=&err&&;&/span&
&/code&&/pre&&/div&&h1&4. JSON 语法子集&/h1&&p&下面是此单元的 JSON 语法子集,使用 &a href=&http://link.zhihu.com/?target=http%3A//rfc7159.net/rfc7159& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&RFC7159&/a& 中的 &a href=&http://link.zhihu.com/?target=https%3A//tools.ietf.org/html/rfc5234& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&ABNF&/a& 表示:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&JSON-text = ws value ws
ws = *(%x20 / %x09 / %x0A / %x0D)
value = null / false / true
false = &false&
&/code&&/pre&&/div&&p&当中 %xhh 表示以 16 进制表示的字符,/ 是多选一,* 是零或多个,( ) 用于分组。&/p&&p&那么第一行的意思是,JSON 文本由 3 部分组成,首先是空白(whitespace),接着是一个值,最后是空白。&/p&&p&第二行告诉我们,所谓空白,是由零或多个空格符(space U+0020)、制表符(tab U+0009)、换行符(LF U+000A)、回车符(CR U+000D)所组成。&/p&&p&第三行是说,我们现时的值只可以是 null、false 或 true,它们分别有对应的字面值(literal)。&/p&&p&我们的解析器应能判断输入是否一个合法的 JSON。如果输入的 JSON 不合符这个语法,我们要产生对应的错误码,方便使用者追查问题。&/p&&p&在这个 JSON 语法子集下,我们定义 3 种错误码:&/p&&ul&&li&若一个 JSON 只含有空白,传回 LEPT_PARSE_EXPECT_VALUE。&/li&&li&若一个值之后,在空白之后还有其他字符,传回 LEPT_PARSE_ROOT_NOT_SINGULAR。&/li&&li&若值不是那三种字面值,传回 LEPT_PARSE_INVALID_VALUE。&/li&&/ul&&h1&5. 单元测试&/h1&&p&许多同学在做练习或刷题时,都是以 printf/cout 打印结果,再用肉眼对比结果是否乎合预期。但当软件项目越来越复杂,这个做法会越来越低效。一般我们会采用自动的测试方式,例如单元测试(unit testing)。单元测试也能确保其他人修改代码后,原来的功能维持正确(这称为回归测试/regression testing)。&/p&&p&常用的单元测试框架有 xUnit 系列,如 C++ 的 &a href=&http://link.zhihu.com/?target=https%3A//github.com/google/googletest& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Google Test&/a&、C# 的 &a href=&http://link.zhihu.com/?target=http%3A//www.nunit.org/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&NUnit&/a&。我们为了简单起见,会编写一个极简单的单元测试方式。&/p&&p&一般来说,软件开发是以周期进行的。例如,加入一个功能,再写关于该功能的单元测试。但也有另一种软件开发方法论,称为测试驱动开发(test-driven development, TDD),它的主要循环步骤是:&/p&&ol&&li&加入一个测试。&/li&&li&运行所有测试,新的测试应该会失败。&/li&&li&编写实现代码。&/li&&li&运行所有测试,若有测试失败回到3。&/li&&li&重构代码。&/li&&li&回到 1。&/li&&/ol&&p&TDD 是先写测试,再实现功能。好处是实现只会刚好满足测试,而不会写了一些不需要的代码,或是没有被测试的代码。&/p&&p&但无论我们是采用 TDD,或是先实现后测试,都应尽量加入足够覆盖率的单元测试。&/p&&p&回到 leptjson 项目,test.c 包含了一个极简的单元测试框架:&/p&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&cp&&#include&/span& &span class=&cpf&&&stdio.h&&/span&&span class=&cp&&&/span&
&span class=&cp&&#include&/span& &span class=&cpf&&&stdlib.h&&/span&&span class=&cp&&&/span&
&span class=&cp&&#include&/span& &span class=&cpf&&&string.h&&/span&&span class=&cp&&&/span&
&span class=&cp&&#include&/span& &span class=&cpf&&&leptjson.h&&/span&&span class=&cp&&&/span&
&span class=&k&&static&/span& &span class=&kt&&int&/span& &span class=&n&&main_ret&/span& &span class=&o&&=&/span& &span class=&mi&&0&/span&&span class=&p&&;&/span&
&span class=&k&&static&/span& &span class=&kt&&int&/span& &span class=&n&&test_count&/span& &span class=&o&&=&/span& &span class=&mi&&0&/span&&span class=&p&&;&/span&
&span class=&k&&static&/span& &span class=&kt&&int&/span& &span class=&n&&test_pass&/span& &span class=&o&&=&/span& &span class=&mi&&0&/span&&span class=&p&&;&/span&
&span class=&cp&&#define EXPECT_EQ_BASE(equality, expect, actual, format) \&/span&
&span class=&cp&&
do {\&/span&
&span class=&cp&&
test_count++;\&/span&
&span class=&cp&&
if (equality)\&/span&
&span class=&cp&&
test_pass++;\&/span&
&span class=&cp&&
else {\&/span&
&span class=&cp&&
fprintf(stderr, &%s:%d: expect: & format & actual: & format &\n&, __FILE__, __LINE__, expect, actual);\&/span&
&span class=&cp&&
main_ret = 1;\&/span&
&span class=&cp&&
&span class=&cp&&
} while(0)&/span&
&span class=&cp&&#define EXPECT_EQ_INT(expect, actual) EXPECT_EQ_BASE((expect) == (actual), expect, actual, &%d&)&/span&
&span class=&k&&static&/span& &span class=&kt&&void&/span& &span class=&nf&&test_parse_null&/span&&span class=&p&&()&/span& &span class=&p&&{&/span&
&span class=&n&&lept_value&/span& &span class=&n&&v&/span&&span class=&p&&;&/span&
&span class=&n&&v&/span&&span class=&p&&.&/span&&span class=&n&&type&/span& &span class=&o&&=&/span& &span class=&n&&LEPT_TRUE&/span&&span class=&p&&;&/span&
&span class=&n&&EXPECT_EQ_INT&/span&&span class=&p&&(&/span&&span class=&n&&LEPT_PARSE_OK&/span&&span class=&p&&,&/span& &span class=&n&&lept_parse&/span&&span class=&p&&(&/span&&span class=&o&&&&/span&&span class=&n&&v&/span&&span class=&p&&,&/span& &span class=&s&&&null&&/span&&span class=&p&&));&/span&
&span class=&n&&EXPECT_EQ_INT&/span&&span class=&p&&(&/span&&span class=&n&&LEPT_NULL&/span&&span class=&p&&,&/span& &span class=&n&&lept_get_type&/span&&span class=&p&&(&/span&&span class=&o&&&&/span&&span class=&n&&v&/span&&span class=&p&&));&/span&
&span class=&p&&}&/span&
&span class=&cm&&/* ... */&/span&
&span class=&k&&static&/span& &span class=&kt&&void&/span& &span class=&nf&&test_parse&/span&&span class=&p&&()&/span& &span class=&p&&{&/span&
&span class=&n&&test_parse_null&/span&&span class=&p&&();&/span&
&span class=&cm&&/* ... */&/span&
&span class=&p&&}&/span&
&span class=&kt&&int&/span& &span class=&nf&&main&/span&&span class=&p&&()&/span& &span class=&p&&{&/span&
&span class=&n&&test_parse&/span&&span class=&p&&();&/span&
&span class=&n&&printf&/span&&span class=&p&&(&/span&&span class=&s&&&%d/%d (%3.2f%%) passed&/span&&span class=&se&&\n&/span&&span class=&s&&&&/span&&span class=&p&&,&/span& &span class=&n&&test_pass&/span&&span class=&p&&,&/span& &span class=&n&&test_count&/span&&span class=&p&&,&/span& &span class=&n&&test_pass&/span& &span class=&o&&*&/span& &span class=&mf&&100.0&/span& &span class=&o&&/&/span& &span class=&n&&test_count&/span&&span class=&p&&);&/span&
&span class=&k&&return&/span& &span class=&n&&main_ret&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&现时只提供了一个 EXPECT_EQ_INT(expect, actual) 的宏,每次使用这个宏时,如果 expect != actual(预期值不等于实际值),便会输出错误信息。 若按照 TDD 的步骤,我们先写一个测试,如上面的 test_parse_null(),而 lept_parse() 只返回 LEPT_PARSE_OK:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&/Users/miloyip/github/json-tutorial/tutorial01/test.c:27: expect: 0 actual: 1
1/2 (50.00%) passed
&/code&&/pre&&/div&&p&第一个返回 LEPT_PARSE_OK,所以是通过的。第二个测试因为 lept_parse() 没有把 v.type 改成 LEPT_NULL,造成失败。我们再实现 lept_parse() 令到它能通过测试。&/p&&p&然而,完全按照 TDD 的步骤来开发,是会减慢开发进程。所以我个人会在这两种极端的工作方式取平衡。通常会在设计 API 后,先写部分测试代码,再写满足那些测试的实现。&/p&&h1&6. 宏的编写技巧&/h1&&p&有些同学可能不了解 EXPECT_EQ_BASE 宏的编写技巧,简单说明一下。反斜线代表该行未结束,会串接下一行。而如果宏里有多过一个语句(statement),就需要用 do { /*&em&...*&/em&/ } while(0) 包裹成单个语句,否则会有如下的问题:&/p&&br&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&cp&&#define M() a(); b()&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&n&&cond&/span&&span class=&p&&)&/span&
&span class=&n&&M&/span&&span class=&p&&();&/span&
&span class=&k&&else&/span&
&span class=&nf&&c&/span&&span class=&p&&();&/span&
&span class=&cm&&/* 预处理后 */&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&n&&cond&/span&&span class=&p&&)&/span&
&span class=&n&&a&/span&&span class=&p&&();&/span& &span class=&n&&b&/span&&span class=&p&&();&/span&
&span class=&k&&else&/span& &span class=&cm&&/* &- else 缺乏对应 if */&/span&
&span class=&n&&c&/span&&span class=&p&&();&/span&
&/code&&/pre&&/div&&p&只用 {} 也不行:&/p&&br&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&cp&&#define M() { a(); b(); }&/span&
&span class=&cm&&/* 预处理后 */&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&n&&cond&/span&&span class=&p&&)&/span&
&span class=&p&&{&/span& &span class=&n&&a&/span&&span class=&p&&();&/span& &span class=&n&&b&/span&&span class=&p&&();&/span& &span class=&p&&};&/span& &span class=&cm&&/* 最后的分号代表 if 语句结束 */&/span&
&span class=&k&&else&/span&
&span class=&cm&&/* else 缺乏对应 if */&/span&
&span class=&n&&c&/span&&span class=&p&&();&/span&
&/code&&/pre&&/div&&p&用 do while 就行了:&/p&&br&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&cp&&#define M() do { a(); b(); } while(0)&/span&
&span class=&cm&&/* 预处理后 */&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&n&&cond&/span&&span class=&p&&)&/span&
&span class=&k&&do&/span& &span class=&p&&{&/span& &span class=&n&&a&/span&&span class=&p&&();&/span& &span class=&n&&b&/span&&span class=&p&&();&/span& &span class=&p&&}&/span& &span class=&k&&while&/span&&span class=&p&&(&/span&&span class=&mi&&0&/span&&span class=&p&&);&/span&
&span class=&k&&else&/span&
&span class=&nf&&c&/span&&span class=&p&&();&/span&
&/code&&/pre&&/div&&h1&7. 实现解析器&/h1&&p&有了 API 的设计、单元测试,终于要实现解析器了。&/p&&p&首先为了减少解析函数之间传递多个参数,我们把这些数据都放进一个 lept_context 结构体:&/p&&br&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&k&&typedef&/span& &span class=&k&&struct&/span& &span class=&p&&{&/span&
&span class=&k&&const&/span& &span class=&kt&&char&/span&&span class=&o&&*&/span& &span class=&n&&json&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&&span class=&n&&lept_context&/span&&span class=&p&&;&/span&
&span class=&cm&&/* ... */&/span&
&span class=&cm&&/* 提示:这里应该是 JSON-text = ws value ws,*/&/span&
&span class=&cm&&/* 以下实现没处理最后的 ws 和 LEPT_PARSE_ROOT_NOT_SINGULAR */&/span&
&span class=&kt&&int&/span& &span class=&nf&&lept_parse&/span&&span class=&p&&(&/span&&span class=&n&&lept_value&/span&&span class=&o&&*&/span& &span class=&n&&v&/span&&span class=&p&&,&/span& &span class=&k&&const&/span& &span class=&kt&&char&/span&&span class=&o&&*&/span& &span class=&n&&json&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&n&&lept_context&/span& &span class=&n&&c&/span&&span class=&p&&;&/span&
&span class=&n&&assert&/span&&span class=&p&&(&/span&&span class=&n&&v&/span& &span class=&o&&!=&/span& &span class=&nb&&NULL&/span&&span class=&p&&);&/span&
&span class=&n&&c&/span&&span class=&p&&.&/span&&span class=&n&&json&/span& &span class=&o&&=&/span& &span class=&n&&json&/span&&span class=&p&&;&/span&
&span class=&n&&v&/span&&span class=&o&&-&&/span&&span class=&n&&type&/span& &span class=&o&&=&/span& &span class=&n&&LEPT_NULL&/span&&span class=&p&&;&/span&
&span class=&n&&lept_parse_whitespace&/span&&span class=&p&&(&/span&&span class=&o&&&&/span&&span class=&n&&c&/span&&span class=&p&&);&/span&
&span class=&k&&return&/span& &span class=&n&&lept_parse_value&/span&&span class=&p&&(&/span&&span class=&o&&&&/span&&span class=&n&&c&/span&&span class=&p&&,&/span& &span class=&n&&v&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&暂时我们只储存 json 字符串当前位置,之后的单元我们需要加入更多内容。&/p&&p&lept_parse() 若失败,会把 v 设为 null 类型,所以这里先把它设为 null,让 lept_parse_value() 写入解析出来的根值。&/p&&p&leptjson 是一个手写的递归下降解析器(recursive descent parser)。由于 JSON 语法特别简单,我们不需要写分词器(tokenizer),只需检测下一个字符,便可以知道它是哪种类型的值,然后调用相关的分析函数。对于完整的 JSON 语法,跳过空白后,只需检测当前字符:&/p&&ul&&li&n ? null&/li&&li&t ? true&/li&&li&f ? false&/li&&li&& ? string&/li&&li&0-9/- ? number&/li&&li&[ ? array&/li&&li&{ ? object&/li&&/ul&&p&所以,我们可以按照 JSON 语法一节的 EBNF 简单翻译成解析函数:&/p&&br&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&cp&&#define EXPECT(c, ch) do { assert(*c-&json == (ch)); c-&json++; } while(0)&/span&
&span class=&cm&&/* ws = *(%x20 / %x09 / %x0A / %x0D) */&/span&
&span class=&k&&static&/span& &span class=&kt&&void&/span& &span class=&nf&&lept_parse_whitespace&/span&&span class=&p&&(&/span&&span class=&n&&lept_context&/span&&span class=&o&&*&/span& &span class=&n&&c&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&const&/span& &span class=&kt&&char&/span& &span class=&o&&*&/span&&span class=&n&&p&/span& &span class=&o&&=&/span& &span class=&n&&c&/span&&span class=&o&&-&&/span&&span class=&n&&json&/span&&span class=&p&&;&/span&
&span class=&k&&while&/span& &span class=&p&&(&/span&&span class=&o&&*&/span&&span class=&n&&p&/span& &span class=&o&&==&/span& &span class=&sc&&' '&/span& &span class=&o&&||&/span& &span class=&o&&*&/span&&span class=&n&&p&/span& &span class=&o&&==&/span& &span class=&sc&&'\t'&/span& &span class=&o&&||&/span& &span class=&o&&*&/span&&span class=&n&&p&/span& &span class=&o&&==&/span& &span class=&sc&&'\n'&/span& &span class=&o&&||&/span& &span class=&o&&*&/span&&span class=&n&&p&/span& &span class=&o&&==&/span& &span class=&sc&&'\r'&/span&&span class=&p&&)&/span&
&span class=&n&&p&/span&&span class=&o&&++&/span&&span class=&p&&;&/span&
&span class=&n&&c&/span&&span class=&o&&-&&/span&&span class=&n&&json&/span& &span class=&o&&=&/span& &span class=&n&&p&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&span class=&cm&&/* null
= &null& */&/span&
&span class=&k&&static&/span& &span class=&kt&&int&/span& &span class=&nf&&lept_parse_null&/span&&span class=&p&&(&/span&&span class=&n&&lept_context&/span&&span class=&o&&*&/span& &span class=&n&&c&/span&&span class=&p&&,&/span& &span class=&n&&lept_value&/span&&span class=&o&&*&/span& &span class=&n&&v&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&n&&EXPECT&/span&&span class=&p&&(&/span&&span class=&n&&c&/span&&span class=&p&&,&/span& &span class=&sc&&'n'&/span&&span class=&p&&);&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&n&&c&/span&&span class=&o&&-&&/span&&span class=&n&&json&/span&&span class=&p&&[&/span&&span class=&mi&&0&/span&&span class=&p&&]&/span& &span class=&o&&!=&/span& &span class=&sc&&'u'&/span& &span class=&o&&||&/span& &span class=&n&&c&/span&&span class=&o&&-&&/span&&span class=&n&&json&/span&&span class=&p&&[&/span&&span class=&mi&&1&/span&&span class=&p&&]&/span& &span class=&o&&!=&/span& &span class=&sc&&'l'&/span& &span class=&o&&||&/span& &span class=&n&&c&/span&&span class=&o&&-&&/span&&span class=&n&&json&/span&&span class=&p&&[&/span&&span class=&mi&&2&/span&&span class=&p&&]&/span& &span class=&o&&!=&/span& &span class=&sc&&'l'&/span&&span class=&p&&)&/span&
&span class=&k&&return&/span& &span class=&n&&LEPT_PARSE_INVALID_VALUE&/span&&span class=&p&&;&/span&
&span class=&n&&c&/span&&span class=&o&&-&&/span&&span class=&n&&json&/span& &span class=&o&&+=&/span& &span class=&mi&&3&/span&&span class=&p&&;&/span&
&span class=&n&&v&/span&&span class=&o&&-&&/span&&span class=&n&&type&/span& &span class=&o&&=&/span& &span class=&n&&LEPT_NULL&/span&&span class=&p&&;&/span&
&span class=&k&&return&/span& &span class=&n&&LEPT_PARSE_OK&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&span class=&cm&&/* value = null / false / true */&/span&
&span class=&cm&&/* 提示:下面代码没处理 false / true,将会是练习之一 */&/span&
&span class=&k&&static&/span& &span class=&kt&&int&/span& &span class=&nf&&lept_parse_value&/span&&span class=&p&&(&/span&&span class=&n&&lept_context&/span&&span class=&o&&*&/span& &span class=&n&&c&/span&&span class=&p&&,&/span& &span class=&n&&lept_value&/span&&span class=&o&&*&/span& &span class=&n&&v&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&switch&/span& &span class=&p&&(&/span&&span class=&o&&*&/span&&span class=&n&&c&/span&&span class=&o&&-&&/span&&span class=&n&&json&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&case&/span& &span class=&sc&&'n'&/span&&span class=&o&&:&/span&
&span class=&k&&return&/span& &span class=&n&&lept_parse_null&/span&&span class=&p&&(&/span&&span class=&n&&c&/span&&span class=&p&&,&/span& &span class=&n&&v&/span&&span class=&p&&);&/span&
&span class=&k&&case&/span& &span class=&sc&&'\0'&/span&&span class=&o&&:&/span& &span class=&k&&return&/span& &span class=&n&&LEPT_PARSE_EXPECT_VALUE&/span&&span class=&p&&;&/span&
&span class=&k&&default&/span&&span class=&o&&:&/span&
&span class=&k&&return&/span& &span class=&n&&LEPT_PARSE_INVALID_VALUE&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&由于 lept_parse_whitespace() 是不会出现错误的,返回类型为 void。其它的解析函数会返回错误码,传递至顶层。&/p&&h1&8. 关于断言&/h1&&p&断言(assertion)是 C 语言中常用的防御式编程方式,减少编程错误。最常用的是在函数开始的地方,检测所有参数。有时候也可以在调用函数后,检查上下文是否正确。&/p&&p&C 语言的标准库含有 assert() 这个宏(需 #include ),提供断言功能。当程序以 release 配置编译时(定义了 NDEBUG 宏),assert() 不会做检测;而当在 debug 配置时(没定义 NDEBUG 宏),则会在运行时检测 assert(cond) 中的条件是否为真(非 0),断言失败会直接令程序崩溃。&/p&&p&初使用断言的同学,可能会把有副作用的代码放在 assert() 中:&/p&&br&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&n&&assert&/span&&span class=&p&&(&/span&&span class=&n&&x&/span&&span class=&o&&++&/span& &span class=&o&&==&/span& &span class=&mi&&0&/span&&span class=&p&&);&/span& &span class=&cm&&/* 这是错误的! */&/span&
&/code&&/pre&&/div&&p&因为这样会导致 debug 和 release 版的行为不一样。&/p&&p&另一个问题是,初学者可能会难于分辨何时使用断言,何时处理运行时错误(如返回错误值或在 C++ 中抛出异常)。简单的答案是,如果那个错误是由于程序员错误编码所造成的(例如传入不合法的参数),那么应用断言;如果那个错误是程序员无法避免,而是由运行时的环境所造成的,就要处理运行时错误(例如开启文件失败)。&/p&&h1&9. 总结与练习&/h1&&p&本文介绍了如何配置一个编程环境,单元测试的重要性,以至于一个 JSON 解析器的子集实现。如果你读到这里,还未动手,建议你快点试一下。以下是本单元的练习,很容易的,但我也会在稍后发出解答篇。&/p&&ol&&li&修正关于 LEPT_PARSE_ROOT_NOT_SINGULAR 的单元测试,若 json 在一个值之后,空白之后还有其它字符,则要返回 LEPT_PARSE_ROOT_NOT_SINGULAR。&/li&&li&参考 test_parse_null(),加入 test_parse_true()、test_parse_false() 单元测试。&/li&&li&参考 lept_parse_null() 的实现和调用方,解析 true 和 false 值。&/li&&/ol&&h1&10. 常见问答&/h1&&ol&&li&&p&为什么把例子命名为 leptjson?&/p&&p&来自于标准模型中的轻子(lepton),意为很轻量的 JSON 库。另外,建议大家为项目命名时,先 google 一下是否够独特,有很多同名的话搜寻时难以命中。&/p&&/li&&li&&p&为什么使用宏而不用函数或内联函数?&/p&&p&因为这个测试框架使用了 __LINE__ 这个编译器提供的宏,代表编译时该行的行号。如果用函数或内联函数,每次的行号便都会相同。另外,内联函数是 C99 的新增功能,本教程使用 C89。&/p&&/li&&/ol&&p&其他常见问答将会从评论中整理。&/p&
本文是的第一个单元。教程练习源代码位于 。 本单元内容: JSON 是什么 搭建编译环境 头文件与 API 设计 JSON 语法子集 单元测试 宏的编写技巧 实现解析器 关于断言 总结与练习 常见问答 (题图
&p&为什么收藏数是赞的两倍多?似乎是知乎定律。&/p&&p&想说说自己Spring的学习路程,课余自学Spring将近一年了,还是不得其道。去年暑假学习了一下JSP,并没有深入理解,所以导致学习Spring时对着书本写一些demo,感觉自己理解了,其实并不知道内部时什么原理,出了问题不停的百度,一个小问题好几天解决不了。&/p&&p& 学习一种框架最先需要知道的是为什么需要使用这个框架,任何一个框架的发明都是为了解决编程中的一些痛点,打开任何一本hibernate或者其他框架的入门书,第一章都是介绍框架的理念和优势。如果需要理解这些理念和优势,那么你需要知道不使用这个框架之前是怎么处理的,才能知道框架做了一些什么事情。&/p&&p& 针对Spring的学习,第一步就是理解IoC和AOP;这是基础;然后学习SpringMVC,其实还是Java EE开发,如果要理解这个框架,就要知道没有这个框架之前,使用的是什么技术。&/p&&blockquote&很多新的技术只不过是引入了新的编程元素对原来技术进行了封装。&br&&/blockquote&&p& Web开发,首先需要理解的是 HTTP协议,这部分一定要深入理解。理解http请求,其实就是要知道下面这张图的含义。&/p&&figure&&img src=&https://pic1.zhimg.com/bfb576a894fbc_b.jpg& data-caption=&& data-rawwidth=&800& data-rawheight=&228& class=&origin_image zh-lightbox-thumb& width=&800& data-original=&https://pic1.zhimg.com/bfb576a894fbc_r.jpg&&&/figure&&p&&br&&/p&&p&还要知道服务器发送给浏览器的响应是没有没有JS,CSS和图片等外部资源的,浏览器在解析响应时才会再次请求这些资源,&b&这里会出现一些静态资源请求不到的问题,SpringMVC是怎么配置的?&/b&&/p&&p& 接下来,学习Servlet和JSP。这个步骤不是可以跳过的,现在流行的框架Spring MVC和Struts2其实都是基于Servlet的,只有深入理解了Servlet才能理解后面的新技术。&/p&&p&下面几个知识点可以检测你是否理解了Servlet:&/p&&p&1、什么是ServletContext,和tomcat等web容器的关系时什么?&a href=&//link.zhihu.com/?target=http%3A//www.ibm.com/developerworks/cn/java/j-lo-servlet/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Servlet 工作原理解析&/a&&/p&&p&简单的说,我们在浏览器点击链接和按钮产生的消息不是发送给Servlet的,而是发送给web容器的(在JSP出现之前,web容器也叫Servlet容器),web容器接收消息后不知道怎么处理,转交给我们编写的Servlet处理,那么web容器怎么和Servlet交流呢?于是就出现了Servlet接口,&b&接口是定义一种规范的良好表达形式。&/b& 只要我们编写的Java类符合Servlet规范,那么就能被Web容器识别并被容器管理。&/p&&p&2、什么是Session?Session在实际工程中的应用场景。以及@SessionAttribute注解的局限性。&/p&&p&3、&b&JSP是面向服务器的&/b&,它并不知道浏览器是什么鬼,是我们在写JSP时预设客户端是浏览器,&b&JSP就是一个Servlet。JSP的常用对象和指令。&/b&&/p&&p&4、JSP的中文编码乱码有几种情况?各自的解决方法?提示: JSP文件的编码,浏览器的解析编码,GET请求的编码,POST的编码。&/p&&p&5、Servlet是一种接口规范,其中请求和响应是Servlet容器通过向方法的参数赋值HttpServletRequest或者HttpServletResponse传递的。在Struts1里面,将doGet()方法里的响应移到返回值里。在Struts2里则:&/p&&ul&&li&在Controller中彻底杜绝引入HttpServletRequest或者HttpServletResponse这样的原生Servlet对象。&/li&&li&同时将请求参数和响应数据都从响应方法中剥离到了Controller中的属性变量。&/li&&/ul&&p&&br&&/p&&p&这是一个很大的技术改造,也造成了Struts2的盛行。Spring MVC走的是中间路线,Spring的2.0.8之前的版本甚至直接使用Servlet的doGet的。Spring MVC现在开始流行主要还是因为Schema xml的精简和基于注解的配置。所以这里出现了新的知识点:Schema Based XML的相关知识和Java5引入的注解原理。&br&参考文献:&br&&a href=&//link.zhihu.com/?target=http%3A//www.iteye.com/blogs/subjects/springmvc-explore& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&博客专栏 - SpringMVC深度探险&/a&&br&强烈推荐看两遍。&br&&br&书籍:推荐许令波的书《深入分析Java Web技术内幕(修订版)》和计文柯的《深入理解spring技术内幕》,特别是第二本,对spring的分析很是彻底。&/p&&p&&br&&/p&&p&
查看源码是比较快的学习方法,在一个项目里直接利用debug的方式追踪变量查看源码,而不是去阅读源码。&/p&&p&如何使用eclipse的debug:&a href=&//link.zhihu.com/?target=http%3A//blog.csdn.net/jackpk/article/details/7655777& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&★ Eclipse Debug 界面应用详解——Eclipse Debug不为人知的秘密&/a&&/p&&p&简单说下步骤:新建一个maven web项目,将需要的依赖都添加到pom中去,在pom文件夹中打开终端,运行&mvn dependency:sources&就可以下载所有pom中依赖的源码。如果是eclipse,选中项目,右键 run as 选择 maven build... ,在goal中填入“dependency:sources”,没有mvn。接着简单写一个mvc项目。假设有一个如下的handler method:我们在方法的第一行打一个断点,进行调试 。&/p&&div class=&highlight&&&pre&&code class=&language-java&&
&span class=&nd&&@RequestMapping&/span&&span class=&o&&(&/span&&span class=&s&&&/&&/span&&span class=&o&&)&/span&
&span class=&kd&&public&/span& &span class=&n&&ModelAndView&/span& &span class=&nf&&indexHandler&/span&&span class=&o&&(){&/span&
&span class=&n&&ModelAndView&/span& &span class=&n&&mv&/span&&span class=&o&&=&/span&&span class=&k&&new&/span& &span class=&n&&ModelAndView&/span&&span class=&o&&(&/span&&span class=&s&&&success&&/span&&span class=&o&&);&/span&
&span class=&n&&mv&/span&&span class=&o&&.&/span&&span class=&na&&addObject&/span&&span class=&o&&(&/span&&span class=&s&&&key&&/span&&span class=&o&&,&/span& &span class=&s&&&hello,hsiung!&&/span&&span class=&o&&);&/span&
&span class=&n&&mv&/span&&span class=&o&&.&/span&&span class=&na&&addObject&/span&&span class=&o&&(&/span&&span class=&s&&&time&&/span&&span class=&o&&,&/span& &span class=&k&&new&/span& &span class=&n&&Date&/span&&span class=&o&&());&/span&
&span class=&k&&return&/span& &span class=&n&&mv&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&p&&br&&/p&&p&一步一步往下看,可以在outline的窗口清楚地看到ModelAndView的属性和方法,可以看到ModelAndView有两个属性很重要,一个是view:O一个是model:ModelMap,接着可以看到上面方法的第二行调用的是如下代码:&/p&&div class=&highlight&&&pre&&code class=&language-text&&public ModelAndView addObject(String attributeName, Object attributeValue) {
getModelMap().addAttribute(attributeName, attributeValue);
&/code&&/pre&&/div&&p&所以model中实际使用的是ModelMap这个类,那这个类的结构是什么呢?按住Ctrl再单击ModelMap,就可以看到其实就是一个LinkedHashMap&String, Object&。&br&
&/p&&p&这里提供非常有用的几个eclipse使用技巧:&br&1.在面向接口编程中,我们很多时候看到一个方法返回的的是静态类型是接口的变量,并且实际类型被方法隐藏了。当然,你可以通过追溯进方法去看。其实一般来说,一个接口,会有一个抽象类,然后会有一个default类,一般想要知道接口的具体实现,去看default类就可以。spring比较特殊,很多默认配置的类不是default开头的。只能靠阅读guide了确定了。&br&2. 看一个类在哪些地方被引用,选中类名,Ctrl+Shift+G,&br&3. 看一个方法在哪些地方被调用,选中方法名,Ctrl+Alt+H。&br&4.学会看eclipse右侧的outline窗口。&/p&&p&---------------------没想到有人看,修改了了一下错别字和细节 -----------------&/p&&p&关于demo,其实spring project提供了一些很好的MVC demo,&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//github.com/spring-projects/spring-mvc-showcase& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&spring-projects/spring-mvc-showcase · GitHub&/a&,&/p&&p&&a href=&//link.zhihu.com/?target=https%3A//github.com/spring-projects/spring-petclinic& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&spring-projects/spring-petclinic · GitHub&/a&。&/p&&p&下载源码,到pom目录下打开终端 运行: mvn eclipse:eclipse ,构建成功后直接导入eclipse就可以运行查看效果了。注意,mvn 命令经常一次不能成功,主要是有些maven插件下载失败以及国内网络的问题,手动删除下载失败的依赖,然后命令多运行几次就可以成功了。也可以使用开源中国的maven源。&/p&&p&&br&&/p&&p&&a href=&//link.zhihu.com/?target=https%3A//github.com/xdahu/xdahu.github.io/wiki& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&xdahu/xdahu.github.io&/a&&/p&
为什么收藏数是赞的两倍多?似乎是知乎定律。想说说自己Spring的学习路程,课余自学Spring将近一年了,还是不得其道。去年暑假学习了一下JSP,并没有深入理解,所以导致学习Spring时对着书本写一些demo,感觉自己理解了,其实并不知道内部时什么原理,出了问…
首先Spring是一个大的概念,Spring从最开始的一个Library到现在一个系列,其中最主要的包括Spring Framework, Spring Data, Spring Security, Spring Batch等等,以及快速框架Spring Boot,其中最重要的项目是Spring Framework,这个项目包括了IoC, AOP, MVC以及Testing。&br&&br&第一个需要明白的是Spring的核心思想是什么?&br&Spring整个系列的最最核心的概念当属IoC, AOP,什么是IoC和AOP就不展开了,简而言之,将对象创建过程的职责赋予容器,通过容器管理对象的生老病死, 将对象创建过程从编译时延期到运行时,即通过配置进行加载,这样一来就解决了不用编译后期选择具体实现,其实就是面向对象的核心理念,针对接口编程。IoC开始就是个factory加上依赖管理罢了,这样一来,一个系统的创建过程就从原先的new改为配置组装,内部通过注入解决了依赖关系,只要满足接口协议即插即用。通过IoC, AOP事实上形成了一个套路,通过这个套路完成了系统的整合。&br&&br&所以Spring并没有说自己写一个ORM,而是用统一的套路完成了多个ORM的集成,这也是Spring越做越大的基础,慢慢就形成了Spring Way,其实这个才是Spring最有价值的地方。&br&&br&第二当然就是一些实践,其实主流问的大概也就几个方向,用的最多的应该就是Spring MVC, Spring Data,
Spring Security和Spring Boot这几块吧,因为毕竟这是实践性内容,很多时候都是show me the code,之前学习过程写过一个sample,基本全是标准Spring Way,你可以拿去参考一下,&a href=&//link.zhihu.com/?target=https%3A//github.com/nonocast/todolist& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&GitHub - nonocast/todolist: A simple todolist system implemented with Spring's backend and TypeScript/React's frontend. Enjoy it.&/a&&br&&br&&figure&&img src=&https://pic4.zhimg.com/ff3a25cfd753_b.jpg& data-rawwidth=&2560& data-rawheight=&1546& class=&origin_image zh-lightbox-thumb& width=&2560& data-original=&https://pic4.zhimg.com/ff3a25cfd753_r.jpg&&&/figure&&br&&figure&&img src=&https://pic4.zhimg.com/bc809a05e3bb8e97a6f85af_b.jpg& data-rawwidth=&2560& data-rawheight=&1546& class=&origin_image zh-lightbox-thumb& width=&2560& data-original=&https://pic4.zhimg.com/bc809a05e3bb8e97a6f85af_r.jpg&&&/figure&&br&&ul&&li&Spring Boot&/li&&li&Spring MVC&/li&&li&Spring Security&/li&&li&Gradle&/li&&li&Freemarker&/li&&li&WebJars&/li&&li&Spring Data JPA&/li&&li&Mysql&/li&&li&Wechat&/li&&li&React&/li&&li&TypeScript&/li&&li&webpack&/li&&li&Redis&/li&&/ul&May it helps.
首先Spring是一个大的概念,Spring从最开始的一个Library到现在一个系列,其中最主要的包括Spring Framework, Spring Data, Spring Security, Spring Batch等等,以及快速框架Spring Boot,其中最重要的项目是Spring Framework,这个项目包括了IoC, AOP, MV…
&figure&&img }

我要回帖

更多关于 攻城掠地192最低配置 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信