这个ca.set()括号怎么向set里面存数据为什么可以这样写,怎么向set里面存数据是获取一个年,一个月,但是最后一个1呢,什么意思

如何使用Python编写一个Lisp解释器 - CSDN博客
如何使用Python编写一个Lisp解释器
原文出处:&&&&译文出处:&
本文有两个目的: 一是讲述实现计算机语言解释器的通用方法,另外一点,着重展示如何使用来实现Lisp方言的一个子集。我将我的解释器称之为Lispy&()。几年前,我介绍过如何,同时我还语言编写过一个版本。这一次,我的目的是尽可能简单明了地演示一下“软件的麦克斯韦方程组”
(Maxwell’s Equations of Software)。
Lispy支持的Scheme子集的语法和语义
大多数计算机语言都有许多语法规约 (例如关键字、中缀操作符、括号、操作符优先级、点标记、分号等等),但是,作为Lisp语言家族中的一员,Scheme所有的语法都是基于包含在括号中的、采用前缀表示的列表的。这种表示看起来似乎有些陌生,但是它具有简单一致的优点。 (一些人戏称”Lisp”是”Lots
of Irritating Silly Parentheses“——“大量恼人、愚蠢的括号“——的缩写;我认为它是”Lisp Is Syntactically Pure“——“Lisp语法纯粹”的缩写。)
考虑下面这个例子:
if(x.val()
f(a*x.val()
(& (val x) 0)
z (f (+
a (val x)) b))))
注意上面的惊叹号在Scheme中并不是一个特殊字符;它只是”set!“这个名字的一部分。(在Scheme中)只有括号是特殊字符。类似于(set!&x
y)这样以特殊关键字开头的列表在Scheme中被称为一个特殊形式 (special form);Scheme的优美之处就在于我们只需要六种特殊形式,以及另外的三种语法构造——变量、常量和过程调用。
形式 (Form)
语义和示例
一个符号,被解释为一个变量名;其值就是这个变量的值。
数字的求值结果为其本身
示例:&12&或者-3.45e+6
(quote&exp)
返回exp的字面值;不对它进行求值。
示例:(quote (a b c)) => (a b c)
(if&test conseq alt)
对test进行求值;如果结果为真,那么对conseq进行求值并返回结果;否则对alt求值并返回结果。
示例:(if (& 10 20) (+ 1 1) (+ 3 3)) => 2
(set!&varexp)
对exp进行求值并将结果赋给var,var必须已经进行过定义 (使用define进行定义或者作为一个封闭过程的参数)。
示例:(set! x2 (* x x))
(define&varexp)
在最内层环境 (environment) 中定义一个新的变量并将对exp表达式求值所得的结果赋给该变量。
示例:(define r 3)&或者&(define
square (lambda (x) (* x x)))
(lambda(var…)exp)
创建一个过程,其参数名字为var…,过程体为相应的表达式。
示例:(lambda (r) (* 3. (* r r)))
(beginexp…)
按从左到右的顺序对表达式进行求值,并返回最终的结果。
示例:(begin (set! x 1) (set! x (+ x 1)) (* x 2)) => 4
(proc exp…)
如果proc是除了if, set!, define, lambda, begin,或者quote之外的其它符号的话,那么它会被视作一个过程。它的求值规则如下:所有的表达式exp都将被求值,然后这些求值结果作为过程的实际参数来调用该相应的过程。
示例:(square 12) => 144
在该表中,var必须是一个符号——一个类似于x或者square这样的标识符——number必须是一个整型或者浮点型数字,其余用斜体标识的单词可以是任何表达式。exp…表示exp的0次或者多次重复。
更多关于Scheme的内容,可以参考一些优秀的书籍 (如,&,,&或者)、视频
()、教程 (、或者)、或者。
语言解释器的职责
一个语言解释器包括两部分:
1、解析 (Parsing):解析部分接受一个使用字符序列表示的输入程序,根据语言的语法规则对输入程序进行验证,然后将程序翻译成一种中间表示。在一个简单的解释器中,中间表示是一种树结构,紧密地反映了源程序中语句或表达式的嵌套结构。在一种称为编译器的语言翻译器中,内部表示是一系列可以直接由计算机
(作者的原意是想说运行时系统——译者注) 执行的指令。正如,“如果你不明白编译器的工作方式,那么你不会明白计算机的工作方式。”Yegge介绍了编译器可以解决的8种问题
(或者解释器,又或者采用Yegge的典型的反讽式的解决方案)。 Lispy的解析器由parse函数实现。
2、执行:程序的内部表示 (由解释器) 根据语言的语义规则进行进一步处理,进而执行源程序的实际运算。(Lispy的)执行部分由eval函数实现
(注意,该函数覆盖了Python内建的同名函数)。
下面的图片描述了解释器的解释流程,(图片后的) 交互会话展示了parse和eval函数对一个小程序的操作方式:
&(begin (define r 3) (* 3. (* r r)))&
parse(program)
['define',
eval(parse(program))
这里,我们采用了一种尽可能简单的内部表示,其中Scheme的列表、数字和符号分别使用Python的列表、数字和字符串来表示。
执行:&eval
下面是eval函数的定义。对于上面表中列出的九种情况,每一种都有一至三行代码,eval函数的定义只需要这九种情况:
env=global_env):
&&&&&Evaluate
an expression in an environment.&
isa(x, Symbol):&&&&&&&&&&&&
&&&&&&&&return
env.find(x)[x]
isa(x, list):&&&&&&&&
&&&&&&&&return
x&&&&&&&&&&&&&&&
'quote':&&&&&&&&&
&&&&&&&&(_,
&&&&&&&&return
'if':&&&&&&&&&&&&
&&&&&&&&(_,
test, conseq, alt) =
&&&&&&&&return
eval((conseq
eval(test,
alt), env)
'set!':&&&&&&&&&&
&&&&&&&&(_,
var, exp) =
&&&&&&&&env.find(var)[var]
'define':&&&&&&&&
&&&&&&&&(_,
var, exp) =
&&&&&&&&env[var]
'lambda':&&&&&&&&
&&&&&&&&(_,
&&&&&&&&return
args, env))
'begin':&&&&&&&&&
&&&&&&&&for
&&&&&&&&&&&&val
&&&&&&&&return
&&&&else:&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&exps
[eval(exp,
&&&&&&&&proc
exps.pop(0)
&&&&&&&&return
proc(*exps)
isinstance
eval函数的定义就是这么多…当然,除了environments。Environments (环境) 只是从符号到符号所代表的值的映射而已。一个新的符号/值绑定由一个define语句或者一个过程定义
(lambda表达式) 添加。
让我们通过一个例子来观察定义然后调用一个Scheme过程的时候所发生的事情 (lis.py&提示符表示我们正在与Lisp解释器进行交互,而不是Python):
(define area (lambda
当我们对(lambda (r) (* 3. (* r r)))进行求值时,我们在eval函数中执行elif
x[0] == 'lambda'分支,将(_, vars, exp)三个变量分别赋值为列表x的对应元素
(如果x的长度不是3,就抛出一个错误)。然后,我们创建一个新的过程,当该过程被调用的时候,将会对表达式['*',
3. ['*', 'r', 'r']]进行求值,该求值过程的环境 (environment) 是通过将过程的形式参数 (该例中只有一个参数,r) 绑定为过程调用时所提供的实际参数,外加当前环境中所有不在参数列表
(例如,变量*) 的变量组成的。新创建的过程被赋值给global_env中的area变量。
那么,当我们对(area 3)求值的时候发生了什么呢?因为area并不是任何表示特殊形式的符号之一,它必定是一个过程调用
(eval函数的最后一个else:分支),因此整个表达式列表都将会被求值,每次求值其中的一个。对area进行求值将会获得我们刚刚创建的过程;对3进行求值所得的结果就是3。然后我们
(根据eval函数的最后一行) 使用参数列表[3]来调用这个新创建的过程。也就是说,对exp(也就是['*',
3. ['*', 'r', 'r']])进行求值,并且求值所在的环境中r的值是3,并且外部环境是全局环境,因此*是乘法过程。
现在,我们可以解释一下Env类的细节了:
Env(dict):
environment: a dict of {'var':val} pairs, with an outer Env.&
__init__(self,
outer=None):
&&&&&&&&self.update(zip(parms,args))
&&&&&&&&self.outer
find(self,
&&&&&&&&&Find
the innermost Env where var appears.&
&&&&&&&&return
self.outer.find(var)
注意Env是dict的一个子类,也就是说,通常的字典操作也适用于Env类。除此之外,该类还有两个方法,构造函数__init__和find函数,后者用来为一个变量查找正确的环境。理解这个类的关键
(以及我们需要一个类,而不是仅仅使用dict的根本原因) 在于外部环境 (outer
environment) 这个概念。考虑下面这个程序:
make-account
&&&&(lambda
&&&&&&(begin
balance (+
balance amt)) balance))))
a1 (make-account
每个矩形框都代表了一个环境,并且矩形框的颜色与环境中最新定义的变量的颜色相对应。在程序的最后两行我们定义了a1并且调用了(a1
-20.00);这表示创建一个开户金额为100美元的银行账户,然后是取款20美元。在对(a1 -20.00)求值的过程中,我们将会对黄色高亮表达式进行求值,该表达式中具有三个变量。amt可以在最内层
(绿色) 环境中直接找到。但是balance在该环境中没有定义:我们需要查看绿色环境的外层环境,也就是蓝色环境。最后,+代表的变量在这两个环境中都没有定义;我们需要进一步查看外层环境,也就是全局
(红色) 环境。先查找内层环境,然后依次查找外部的环境,我们把这一过程称之为词法定界&(lexical scoping)。Procedure.find负责根据词法定界规则查找正确的环境。
剩下的就是要定义全局环境。该环境需要包含+过程以及所有其它Scheme的内置过程。我们并不打算实现所有的内置过程,但是,通过导入Python的math模块,我们可以获得一部分这些过程,然后我们可以显式地添加20种常用的过程:
add_globals(env):
some Scheme standard procedures to an environment.&
&&&&import
math, operator as op
&&&&env.update(vars(math))
&&&&env.update(
&&&&&{'+':op.add,
'-':op.sub,
'*':op.mul,
'/':op.div,
'not':op.not_,
&&&&&&'&':op.gt,
'&':op.lt,
'&=':op.ge,
'&=':op.le,
'=':op.eq,
&&&&&&'equal?':op.eq,
'eq?':op.is_,
'length':len,
'cons':lambda
x,y:[x]+y,
&&&&&&'car':lambda
x:x[0],'cdr':lambda
'append':op.add,&
&&&&&&'list':lambda
*x:list(x),
x:isa(x,list),
&&&&&&'null?':lambda
'symbol?':lambda
x: isa(x, Symbol)})
&&&&return
global_env
add_globals(Env())
PS1: 对麦克斯韦方程组的一种评价是“一般地,宇宙间任何的电磁现象,皆可由此方程组解释”。Alan Kay所要表达的,大致就是Lisp语言使用自身定义自身 (Lisp was “defined in terms of Lisp”) 这种自底向上的设计对软件设计而言具有普遍的参考价值。——译者注
解析 (Parsing):&read和parse
接下来是parse函数。解析通常分成两个部分:词法分析和语法分析。前者将输入字符串分解成一系列的词法单元&(token);后者将词法单元组织成一种中间表示。Lispy支持的词法单元包括括号、符号
(如set!或者x)
以及数字 (如2)。它的工作形式如下:
&(set! x*2 (* x 2))&
tokenize(program)
parse(program)
有许多工具可以进行词法分析 (例如Mike Lesk和Eric Schmidt的)。但是我们将会使用一个非常简单的工具:Python的str.split。我们只是在
(源程序中) 括号的两边添加空格,然后调用str.split来获得一个词法单元的列表。
接下来是语法分析。我们已经看到,Lisp的语法很简单。但是,一些Lisp解释器允许接受表示列表的任何字符串作为一个程序,从而使得语法分析的工作更加简单。换句话说,字符串(set!
1 2)可以被接受为是一个语法上有效的程序,只有当执行的时候解释器才会抱怨set!的第一个参数应该是一个符号,而不是数字。在Java或者Python中,与之等价的语句1
= 2将会在编译时被认定是错误。另一方面,Java和Python并不需要在编译时检测出表达式x/0是一个错误,因此,如你所见,一个错误应该何时被识别并没有严格的规定。Lispy使用read函数来实现parse函数,前者用以读取任何的表达式
(数字、符号或者嵌套列表)。
tokenize函数获取一系列词法单元,read通过在这些词法单元上调用read_from函数来进行工作。给定一个词法单元的列表,我们首先查看第一个词法单元;如果它是一个’)’,那么这是一个语法错误。如果它是一个’(‘,那么我们开始构建一个表达式列表,直到我们读取一个匹配的’)’。所有其它的
(词法单元) 必须是符号或者数字,它们自身构成了一个完整的列表。剩下的需要注意的就是要了解’2‘代表一个整数,2.0代表一个浮点数,而x代表一个符号。我们将区分这些情况的工作交给Python去完成:对于每一个不是括号也不是引用
(quote) 的词法单元,我们首先尝试将它解释为一个int,然后尝试float,最后尝试将它解释为一个符号。根据这些规则,我们得到了如下程序:
a Scheme expression from a string.&
&&&&return
read_from(tokenize(s))
tokenize(s):
&&&&&Convert
a string into a list of tokens.&
&&&&return
s.replace('(','
( ').replace(')','
) ').split()
read_from(tokens):
an expression from a sequence of tokens.&
len(tokens)
&&&&&&&&raise
SyntaxError('unexpected
EOF while reading')
tokens.pop(0)
&&&&&&&&while
&&&&&&&&&&&&L.append(read_from(tokens))
&&&&&&&&tokens.pop(0)
&&&&&&&&return
&&&&&&&&raise
SyntaxError('unexpected
&&&&&&&&return
atom(token)
atom(token):
&&&&&Numbers
every other token is a symbol.&
int(token)
&&&&except
ValueError:
&&&&&&&&try:
float(token)
&&&&&&&&except
ValueError:
&&&&&&&&&&&&return
Symbol(token)
最后,我们将要添加一个函数to_string,用来将一个表达式重新转换成Lisp可读的字符串;以及一个函数repl,该函数表示read-eval-print-loop
(读取-求值-打印循环),用以构成一个交互式的Lisp解释器:
to_string(exp):
&&&&&Convert
a Python object back into a Lisp-readable string.&
&&&&return
'.join(map(to_string,
exp))+')'
isa(exp, list)
repl(prompt='lis.py&
prompt-read-eval-print loop.&
&&&&&&&&val
eval(parse(raw_input(prompt)))
&&&&&&&&if
to_string(val)
下面是函数工作的一个例子:
(define area (lambda
(define fact (lambda
n (fact (-
(fact 100)
(area (fact 10))
4.e+13
(define first car)
(define rest cdr)
(define count (lambda
(item L) (if
(equal? item (first L)) (count item (rest L))) 0)))
(count (quote the) (quote (the more the merrier the bigger the better)))
Lispy有多小、多快、多完备、多优秀?
我们使用如下几个标准来评价Lispy:
*小巧:Lispy非常小巧:不包括注释和空白行,其源代码只有90行,并且体积小于4K。(比第一个版本的体积要小,第一个版本有96行——根据Eric
Cooper的建议,我删除了Procedure的类定义,转而使用Python的lambda。)
我用Java编写的Scheme解释器最小的版本,其源代码也有1664行、57K。Jscheme最初被称为SILK (Scheme in Fifty Kilobytes——50KB的Scheme解释器),但是只有计算字节码而不是源代码的时候,我才能保证
(其体积) 小于该最小值。Lispy做的要好得多;我认为它满足了Alan Kay在1972年的:他声称我们可以使用“一页代码”来定义“世界上最强大的语言”。
grep &^\s*[^#\s]&
lis.py | wc
&&&&&&90&&&&
*高效:Lispy计算(fact
100)只需要0.004秒。对我来说,这已经足够快了 (虽然相比起其它的计算方式来说要慢很多)。
*完备:相比起Scheme标准来说,Lispy不是非常完备。主要的缺陷有:
(1)&语法:缺少注释、引用 (quote) / 反引用 (quasiquote) 标记 (即'和`——译者注)、#字面值
(例如#\a——译者注)、衍生表达式类型 (例如从if衍生而来的cond,或者从lambda衍生而来的let),以及点列表
(dotted list)。
(2)&语义:缺少call/cc以及尾递归。
(3)&数据类型:缺少字符串、字符、布尔值、端口 (ports)、向量、精确/非精确数字。事实上,相比起Scheme的pairs和列表,Python的列表更加类似于Scheme的向量。
(4)&过程:缺少100多个基本过程:与缺失数据类型相关的所有过程,以及一些其它的过程 (如set-car!和set-cdr!,因为使用Python的列表,我们无法完整实现set-cdr!)。
(5)&错误恢复:Lispy没有尝试检测错误、合理地报告错误以及从错误中恢复。Lispy希望程序员是完美的。
*优秀:这一点需要读者自己确定。我觉得,相对于我解释Lisp解释器这一目标而言,它已经足够优秀。
真实的故事
了解解释器的工作方式会很有帮助,有一个故事可以支持这一观点。1984年的时候,我在撰写我的博士论文。当时还没有LaTeX和Microsoft Word——我们使用的是troff。遗憾的是,troff中没有针对符号标签的前向引用机制:我想要能够撰写“正如我们将要在@theoremx页面看到的”,随后在合适的位置撰写”@(set theoremx \n%)” (troff寄存器\n%保存了页号)。我的同伴,研究生Tony
DeRose也有着同样的需求,我们一起实现了一个简单的Lisp程序,使用这个程序作为一个预处理器来解决我们的问题。然而,事实证明,当时我们用的Lisp善于读取Lisp表达式,但在采用一次一个字符的方式读取非Lisp表达式时效率过低,以至于我们的这个程序很难使用。
在这个问题上,Tony和我持有不同的观点。他认为 (实现) 表达式的解释器是困难的部分;他需要Lisp为他解决这一问题,但是他知道如何编写一个短小的C过程来处理非Lisp字符,并知道如何将其链接进Lisp程序。我不知道如何进行这种链接,但是我认为为这种简单的语言编写一个解释器 (其所具有的只是设置变量、获取变量值和字符串连接) 很容易,于是我使用C语言编写了一个解释器。因此,戏剧性的是,Tony编写了一个Lisp程序,因为他是一个C程序员;我编写了一个C程序,因为我是一个Lisp程序员。
最终,我们都完成了我们的论文。
整个解释器
重新总结一下,下面就是Lispy的所有代码 (也可以从下载):
本文已收录于以下专栏:
相关文章推荐
mal是一个受Clojure启发的Lisp解释器,使用到了56种语言,其每一次的实现都会被分割成11个独立的步骤。...
感谢@李欲纯 的热心翻译。如果其他朋友也有不错的原创或译文,可以尝试推荐给伯乐在线。】
Little Lisp是一个解释器,支持函数调用、lambda表达式、 变量绑定(let)、数字、字符串、...
lisp的解释器
Time Limit: 2000 MS
Memory Limit: 65535 Kb
Total Submission: 22
Accepted: ...
几个免费的Scheme(Lisp)解释器
关键字: lisp scheme
Lisp是一个古老的函数式编程语言,Scheme则起源于MIT的一种Lisp方言。当前编程语言的一些特...
原文地址:Making a simple VM interpreter in Python更新:根据大家的评论我对代码做了轻微的改动。感谢 robin-gvx、 bs4h 和 Dagur,具体代码见这...
使用JavaScript实现一个“字节码解释器”,并用它重新实现JS科学计算器的后端(后续1)
https://codereview.chromium.org//...
成功解决了字节码指令生成的问题,掌握一个原则:
1、数值常量一律MovImm #imm, R0,但把执行Push
2、假设任何表达式的指令生成结果都对应于其值在R0里,要不要Push iff:
字节码设计:第一版(仅仅用于表达式计算)
PushImm 123
Mov src, dst #寄存器到寄存器
MovImm imm, reg #加载立即数到寄存器
反省一下我目前的字节码指令设计:
1、CallPrimitiveFunction是基于寄存器的,有一个最简单的ABI,但中间的临时变量却是需要Push/Pop的,什么时候需要将原语函数的计算结果Pu...
在使用Python编写Hadoop Streaming作业的过程中,我们发现需要使用一些比较复杂的第三方库,比如numpy,scipy,scikit-learn,pandas等等。而这些库通过简单的z...
他的最新文章
讲师:董岩
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)java 里面new一个类的同时后面一个大括号里面一个方法是什么?_java吧_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0成为超级会员,使用一键签到本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:670,309贴子:
java 里面new一个类的同时后面一个大括号里面一个方法是什么?收藏
java 里面new一个类的同时后面一个大括号里面一个方法是什么?代码来自核心技术I,p247求大神指教public class SizedFrameTest {
public static void main(String[] args){
EventQueue.invokeLater(new Runnable(){
public void run(){
SizedFrame sf=new SizedFrame();
sf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
sf.setVisible(true);
}}中间这一段new Runnable(){
public void run(){
SizedFrame sf=new SizedFrame();
sf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
sf.setVisible(true);
}});没见那里提到过这样的用法
自学web前端,html5,css,js免费教程,web前端入门到精通,成为前端开发工程师...
匿名内部类
EventQueue.invokeLater方法的参数是一个Runnable runnable,但是Runnable是一个接口,也就是说这里需要传入一个实现类的实例,你可以自己写一个类来实现Runnable接口,在这个类中重写run方法,然后将这个类的实例传入EventQueue.invokeLater方法但如果你这个类只有这一个地方用,其他地方不会用到,你就可以直接写new Runnable(){}这样的形式,表示这是一个实现了Runnable接口的匿名内部类
青铜星玩家
百度移动游戏玩家均可认证(限百度账号),
匿名类,这段代码等效于new RunnableImpl(); class RunnableImpl implement Runnable {public void run(){ SizedFrame sf=new SizedFrame(); sf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); sf.setVisible(true);}}
这个就是匿名类 假的类
需要完成 接口中的方法
匿名内部类
登录百度帐号推荐应用&figure&&img src=&/50/v2-dba7e7f875b69c46f00724_b.jpg& data-rawwidth=&1195& data-rawheight=&705& class=&origin_image zh-lightbox-thumb& width=&1195& data-original=&/50/v2-dba7e7f875b69c46f00724_r.jpg&&&/figure&&blockquote&&p&具备基本工程素养的同学都会注重编码规范,而代码风格检查(Code Linting,简称 Lint)是保障代码规范一致性的重要手段,你的工作流中有 Lint 环节么?有的话你用的爽么?你在团队中推广过 Lint,但是大家都不买账?究竟是为啥?&/p&&/blockquote&&h2&Lint 是什么?&/h2&&p&探讨怎么做之前,我们很有必要给 Lint 来个清晰、准确的定义,&a href=&/?target=https%3A//en.wikipedia.org/wiki/Lint_%28software%29& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&wikipedia 的定义&i class=&icon-external&&&/i&&/a&如下:&/p&&blockquote&&p&In computer programming, lint is a Unix utility that flags some suspicious and non-portable constructs (likely to be bugs) in C
generically, lint or a linter is any tool that flags suspicious usage in software written in any computer language. The term lint-like behavior is sometimes applied to the process of flagging suspicious language usage. Lint-like tools generally perform static analysis of source code.&/p&&/blockquote&&p&简单来说,Lint 就是对代码做静态分析,并试图找出潜在问题的工具,实战中我们也用 Lint 来指使用工具的过程。&/p&&h2&为什么要 Lint?&/h2&&p&使用 Lint 会有什么好处呢?在我看来至少具有如下 3 点:&/p&&ul&&li&更少的 Bug,剑桥大学的&a href=&/?target=http%3A///releases/2013/1/prweb.htm& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&研究&i class=&icon-external&&&/i&&/a&发现,全世界每年因为软 Bug 造成的经济损失约 3120 亿美金;&/li&&li&更高的开发效率,工程师平均会花掉 50% 的工作时间定位和解决各种 Bug,其中不乏那些显而易见的低级错误,而 Lint 很容易发现低级的、显而易见的错误;&/li&&li&更高的可读性,代码可读性的首要因子是“表面文章”,表面上看起来乱糟糟的代码通常更难读懂;&/li&&/ul&&p&可以毫不客气的说,如果你不做 Lint,就是在浪费自己的时间,浪费公司的资源。既然做 Lint 的预期效果很好?该怎么做呢?&/p&&h2&提交后 Lint:反馈链条太长?&/h2&&p&说到怎么做,多数人会自然而然的想到各种 Lint 工具,目前社区中针对各种语言都开发了 Lint 工具,前端能用到的就有大把:&a href=&/?target=http%3A//eslint.org/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&ESLint&i class=&icon-external&&&/i&&/a&、&a href=&/?target=https%3A///index.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Standard&i class=&icon-external&&&/i&&/a&、&a href=&/?target=https%3A///brigade/scss-lint& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&SCSSLint&i class=&icon-external&&&/i&&/a&、&a href=&/?target=https%3A///zaach/jsonlint& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&JSONLint&i class=&icon-external&&&/i&&/a&、&a href=&/?target=https%3A///yaniswang/HTMLHint& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&HTMLHint&i class=&icon-external&&&/i&&/a& 等。GitHub 官方出品的 &a href=&/?target=https%3A///showcases/clean-code-linters& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Lint 工具列表&i class=&icon-external&&&/i&&/a& 也是个非常不错的参考。&/p&&p&很多同学选择在持续集成阶段(后文用 CI 代称)做 Lint,比如使用远程的 Git Hooks 来触发。但是从实际的经历来看,这种做法的反馈链条通常如下:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&代码提交 --& 发现问题(远程) --& 修复问题 --& 重新提交 --& 通过检查(远程)
&/code&&/pre&&/div&&p&整个过程可能会浪费掉你不少时间,毕竟 CI 过程通常不仅是在做 Lint,如果你是那种不知道自己时间每天都去哪儿了的工程师,可以反思下自己或者团队的工作流是否是这样。并且,请相信我,你不是少数人。&/p&&p&你有没有这样的经历:吭哧吭哧写了几天代码,各种验收都通过了,最后被 CI 拒绝,竟是因为你的代码中少加了一个逗号,这时候心情简直崩溃到无法形容:&/p&&br&&img src=&/v2-48faa9dcd12_b.jpg& data-rawwidth=&500& data-rawheight=&357& data-thumbnail=&/v2-48faa9dcd12_b.jpg& class=&origin_image zh-lightbox-thumb& width=&500& data-original=&/v2-48faa9dcd12_r.gif&&&br&&p&从 GitHub 上各种修复 Lint 的提交数量不难发现工程师在修复 Lint 问题上浪费的时间,比如搜索 &fix lint&,多达 45W 次提交:&/p&&br&&img src=&/v2-caf51cb12d310f700d7663_b.png& data-rawwidth=&934& data-rawheight=&424& class=&origin_image zh-lightbox-thumb& width=&934& data-original=&/v2-caf51cb12d310f700d7663_r.png&&&br&&p&再比如搜索 “fix indent”,多达 226W 次提交,是不是很触目惊心?&/p&&br&&img src=&/v2-505c8e7d52ab0c70be1a7_b.png& data-rawwidth=&942& data-rawheight=&428& class=&origin_image zh-lightbox-thumb& width=&942& data-original=&/v2-505c8e7d52ab0c70be1a7_r.png&&&br&&p&只在 CI 流程做 Lint 的缺点也是显而易见的:&/p&&ul&&li&Lint 在整个开发工作流中的反馈链条太长,浪费时间、注意力和资源,最致命的;&/li&&li&CI 流程搭建成本比较高,即使有各种 CI 服务,步骤也还是比较繁琐;&/li&&/ul&&p&我们该怎么改进?&/p&&h2&提交前 Lint:错误信息不相关?&/h2&&p&为了缩短 Lint 的反馈链条,把 Lint 挪到本地是最有效的办法。常见做法是使用 &a href=&/?target=https%3A///typicode/husky& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&husky&i class=&icon-external&&&/i&&/a& 或者 &a href=&/?target=https%3A///observing/pre-commit& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&pre-commit&i class=&icon-external&&&/i&&/a& 在本地提交之前做 Lint。&/p&&p&使用 husky 的具体做法如下:&/p&&p&首先,安装依赖:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&npm install -D husky
yarn add --dev husky
&/code&&/pre&&/div&&p&然后修改 package.json,增加配置:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&{
&scripts&: {
&precommit&: &eslint src/**/*.js&
&/code&&/pre&&/div&&p&最后尝试 Git 提交,你就会很快收到反馈:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&git commit -m &Keep calm and commit&
&/code&&/pre&&/div&&p&但是在遗留代码仓库上工作的同学很快会遇到新的问题,开启 Lint 初期,你可能会面临成千上万的 Lint Error 需要修复。部分同学对下面这个图可能并不陌生:只改了文件 A,但是文件 B、C、D 中也有大量错误。&/p&&br&&img src=&/v2-e74f8cf1e75ea00c38012ae_b.png& data-rawwidth=&1308& data-rawheight=&472& class=&origin_image zh-lightbox-thumb& width=&1308& data-original=&/v2-e74f8cf1e75ea00c38012ae_r.png&&&br&&p&把整个仓库都格式化不失为一种选择,但是实际上需要很大的勇气。多数人在项目中运用新工具都希望是渐进式的,而不是推到重来式的,因为相比而言,业务系统稳定是更重要的事情。简单的把 Lint 挪到本地,反馈链条是缩短了,但是面对每次改动,工具还是给出了太多不相关的信息,这无疑与小步快跑的互联网节奏是相违背的。&/p&&p&该怎么破?&/p&&h2&只 Lint 改动的:66666&/h2&&p&如果把 Lint 挪到本地,并且每次提交只检查本次提交所修改的文件,上面的痛点就都解决了。Feedly 的工程师 &a href=&/?target=https%3A///%7Eokonet& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Andrey Okonetchnikov&i class=&icon-external&&&/i&&/a& 开发的 &a href=&/?target=https%3A///okonet/lint-staged& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&lint-staged&i class=&icon-external&&&/i&&/a& 就是基于这个想法,其中 staged 是 Git 里面的概念,指待提交区,使用 git commit -a,或者先 git add 然后 git commit 的时候,你的修改代码都会经过待提交区。&/p&&p&lint-staged 用法如下:&/p&&p&首先,安装依赖:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&npm install -D lint-staged
yarn add --dev lint-staged
&/code&&/pre&&/div&&p&然后,修改 package.json 配置:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&{
&scripts&: {
&precommit&: &lint-staged&
&lint-staged&: {
&src/**/*.js&: &eslint&
&/code&&/pre&&/div&&p&最后,尝试提交的效果:&/p&&br&&img src=&/v2-ab77f2e2f76f0a2b47fdb798b61b4671_b.jpg& data-rawwidth=&828& data-rawheight=&568& data-thumbnail=&/v2-ab77f2e2f76f0a2b47fdb798b61b4671_b.jpg& class=&origin_image zh-lightbox-thumb& width=&828& data-original=&/v2-ab77f2e2f76f0a2b47fdb798b61b4671_r.gif&&&br&&p&实际上,lint-staged 给了你提交前代码操作的更大自由度,比如使用下面的配置,自动修复错误:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&{
&scripts&: {
&precommit&: &lint-staged&
&lint-staged&: {
&src/**/*.js&: [&eslint --fix&, &git add&]
&/code&&/pre&&/div&&p&或者使用下面的配置,自动格式化代码(谨慎使用):&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&{
&scripts&: {
&precommit&: &lint-staged&
&lint-staged&: {
&src/**/*.js&: [&prettier --write&, &git add&]
&/code&&/pre&&/div&&p&此外,lint-staged 和 prettier &a href=&/?target=https%3A///facebookincubator/create-react-app/pull/1759& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&已经集成到 create-react-app 中了&i class=&icon-external&&&/i&&/a&。你是不是也应该好好打磨下自己的 Lint 工作流了?&/p&&h2&总结&/h2&&p&有人说前端攻城狮是世界上最奇怪的动物,提交代码时用 prettier 把代码排版的很美观,但部署上线时又使用 uglify 把代码压缩的连亲妈都不认了,事实是,如果我们写出来的代码本来就很丑陋,就根本不需要用 uglify。希望读到这里的你能把 Lint 工作流打磨到极致,把更多时间专注在解决真正的问题上,成为真正高效的工程师。&/p&&h2&One More Thing&/h2&&p&本文作者王仕军,商业转载请联系作者获得授权,非商业转载请注明出处。如果你觉得本文对你有帮助,请点赞!如果对文中的内容有任何疑问,欢迎留言讨论。想知道我接下来会写些什么?欢迎订阅我的&a href=&/?target=https%3A//juejin.im/user/57a7f634d342dd& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&掘金专栏&i class=&icon-external&&&/i&&/a&或&a href=&/feweekly& class=&internal&&知乎专栏&/a&:《前端周刊:让你在前端领域跟上时代的脚步》。&/p&
具备基本工程素养的同学都会注重编码规范,而代码风格检查(Code Linting,简称 Lint)是保障代码规范一致性的重要手段,你的工作流中有 Lint 环节么?有的话你用的爽么?你在团队中推广过 Lint,但是大家都不买账?究竟是为啥?Lint 是什么?探讨怎么做之…
&figure&&img src=&/50/v2-891df18bb7e8_b.png& data-rawwidth=&544& data-rawheight=&507& class=&origin_image zh-lightbox-thumb& width=&544& data-original=&/50/v2-891df18bb7e8_r.png&&&/figure&&p&上一篇……&/p&&p&&a href=&/p/& class=&internal&&C语言学习笔记——FP in C(1)&/a&&/p&&p&&br&&/p&&p&我们每个星期都有一节上机课,那时我才有时间鼓捣C语言。(捂脸,其实是因为懒……)正所谓乱搞出真知……我又接触了一点点GCC对C语言的一些语法扩展。看来又可以实现一些fp的一些功能了。(GCC真的强大……)&/p&&p&&br&&/p&&p&上一篇我们尝试了在C语言里使用函数指针实现高阶函数,柯里化;当然还尝试了GCC的实现闭包的拓展(内嵌函数)。&/p&&p&那么这一篇我们也尝试下利用GCC对C的拓展实现下Lambda?&/p&&p&&br&&/p&&p&那么就稍微简单介绍下我们需要用到的拓展:&/p&&p&1、语句表达式(&a href=&/?target=https%3A//gcc.gnu.org/onlinedocs/gcc-5.2.0/gcc/Statement-Exprs.html%23Statement-Exprs& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Statements Expressions&i class=&icon-external&&&/i&&/a&)&/p&&p&(我……并不知道是不是这样翻译的= =搜了下百度,也有人叫内嵌表达式。。不管了。)&/p&&p&格式: &img src=&/equation?tex=%3C%E8%A1%A8%E8%BE%BE%E5%BC%8F%3E%3A%3D%5Cleft%28+%5Cleft%5C%7B+%E8%AF%AD%E5%8F%A51%3B%E8%AF%AD%E5%8F%A52%3B...%3B%E8%A1%A8%E8%BE%BE%E5%BC%8F%3B+%5Cright%5C%7D%5Cright%29& alt=&&表达式&:=\left( \left\{ 语句1;语句2;...;表达式; \right\}\right)& eeimg=&1&&&/p&&p&语句表达式的值为({})里最后一个表达式的值。(这其实scala里的块表达式还是挺相似的)&/p&&p&简单的例子:&/p&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&kt&&int&/span& &span class=&nf&&main&/span&&span class=&p&&(&/span&&span class=&kt&&void&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&kt&&int&/span& &span class=&n&&max&/span&&span class=&p&&;&/span&
&span class=&n&&max&/span& &span class=&o&&=&/span& &span class=&p&&({&/span&
&span class=&kt&&int&/span& &span class=&n&&a&/span&&span class=&p&&,&/span&&span class=&n&&b&/span&&span class=&p&&;&/span&
&span class=&n&&scanf&/span&&span class=&p&&(&/span&&span class=&s&&&%d %d&&/span&&span class=&p&&,&/span&&span class=&o&&&&/span&&span class=&n&&a&/span&&span class=&p&&,&/span&&span class=&o&&&&/span&&span class=&n&&b&/span&&span class=&p&&);&/span&
&span class=&n&&a&/span&&span class=&o&&&&/span&&span class=&n&&b&/span&&span class=&o&&?&/span&&span class=&nl&&a&/span&&span class=&p&&:&/span&&span class=&n&&b&/span&&span class=&p&&;&/span&
&span class=&p&&});&/span&
&span class=&n&&printf&/span&&span class=&p&&(&/span&&span class=&s&&&%d&/span&&span class=&se&&\n&/span&&span class=&s&&&&/span&&span class=&p&&,&/span& &span class=&n&&max&/span&&span class=&p&&);&/span&
&span class=&k&&return&/span& &span class=&mi&&0&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&测试效果:&/p&&figure&&img data-rawheight=&85& src=&/50/v2-f49544aec44ab01529b0ffa398abe4b8_b.jpg& data-rawwidth=&183& class=&content_image& width=&183&&&/figure&&p&好像看起来并没有什么卵用,完全可以这样写:&/p&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&kt&&int&/span& &span class=&nf&&main&/span&&span class=&p&&(&/span&&span class=&kt&&void&/span&&span class=&p&&){&/span&
&span class=&kt&&int&/span& &span class=&n&&max&/span&&span class=&p&&;&/span&
&span class=&p&&{&/span&
&span class=&kt&&int&/span& &span class=&n&&a&/span&&span class=&p&&,&/span&&span class=&n&&b&/span&&span class=&p&&;&/span&
&span class=&n&&scanf&/span&&span class=&p&&(&/span&&span class=&s&&&%d %d&&/span&&span class=&p&&,&/span&&span class=&o&&&&/span&&span class=&n&&a&/span&&span class=&p&&,&/span&&span class=&o&&&&/span&&span class=&n&&b&/span&&span class=&p&&);&/span&
&span class=&n&&max&/span& &span class=&o&&=&/span& &span class=&n&&a&/span&&span class=&o&&&&/span&&span class=&n&&b&/span&&span class=&o&&?&/span&&span class=&nl&&a&/span&&span class=&p&&:&/span&&span class=&n&&b&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&span class=&n&&printf&/span&&span class=&p&&(&/span&&span class=&s&&&%d&/span&&span class=&se&&\n&/span&&span class=&s&&&&/span&&span class=&p&&,&/span&&span class=&n&&max&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&但是语句表达式可以结合宏使用,可以写出意想不到的功能。&/p&&p&这个表达式,在一些情况其实可以用逗号运算符来代替:&/p&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&kt&&int&/span& &span class=&nf&&main&/span&&span class=&p&&(&/span&&span class=&kt&&void&/span&&span class=&p&&){&/span&
&span class=&kt&&int&/span& &span class=&n&&max&/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=&n&&max&/span& &span class=&o&&=&/span& &span class=&p&&(&/span&&span class=&n&&scanf&/span&&span class=&p&&(&/span&&span class=&s&&&%d %d&&/span&&span class=&p&&,&/span&&span class=&o&&&&/span&&span class=&n&&a&/span&&span class=&p&&,&/span&&span class=&o&&&&/span&&span class=&n&&b&/span&&span class=&p&&),&/span&&span class=&n&&a&/span&&span class=&o&&&&/span&&span class=&n&&b&/span&&span class=&o&&?&/span&&span class=&nl&&a&/span&&span class=&p&&:&/span&&span class=&n&&b&/span&&span class=&p&&);&/span&
&span class=&n&&printf&/span&&span class=&p&&(&/span&&span class=&s&&&%d&/span&&span class=&se&&\n&/span&&span class=&s&&&&/span&&span class=&p&&,&/span&&span class=&n&&max&/span&&span class=&p&&);&/span&
&span class=&k&&return&/span& &span class=&mi&&0&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&逗号表达式怎么用我就不说了……这是标准C里也有的。用起来并不像上面的直观、好用,而且不能定义局部变量。&/p&&p&(住口!无耻小贼!怎么可以这样写代码!)&/p&&p&&br&&/p&&p&2、&a href=&/?target=https%3A//gcc.gnu.org/onlinedocs/gcc-5.2.0/gcc/Typeof.html%23Typeof& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&typeof&i class=&icon-external&&&/i&&/a&&/p&&p&typeof()是个很屌的东西……直接看例子:&/p&&p&括号里面可以塞进一个类型:&/p&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&kt&&int&/span& &span class=&n&&x&/span&&span class=&p&&;&/span&
&span class=&n&&typeof&/span&&span class=&p&&(&/span&&span class=&kt&&int&/span& &span class=&o&&*&/span&&span class=&p&&)&/span& &span class=&n&&px&/span& &span class=&o&&=&/span& &span class=&o&&&&/span&&span class=&n&&x&/span&&span class=&p&&;&/span&
&/code&&/pre&&/div&&p&这样的效果相当于&/p&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&kt&&int&/span& &span class=&n&&x&/span&&span class=&p&&;&/span&
&span class=&kt&&int&/span& &span class=&o&&*&/span& &span class=&n&&px&/span& &span class=&o&&=&/span& &span class=&o&&&&/span&&span class=&n&&x&/span&&span class=&p&&;&/span&
&/code&&/pre&&/div&&p&当然这样看不出typeof的威力,我们还可以这样写:&/p&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&kt&&int&/span& &span class=&nf&&main&/span&&span class=&p&&(&/span&&span class=&kt&&void&/span&&span class=&p&&){&/span&
&span class=&n&&typeof&/span&&span class=&p&&(&/span&&span class=&kt&&int&/span& &span class=&p&&(&/span&&span class=&o&&*&/span&&span class=&p&&)(&/span&&span class=&kt&&int&/span&&span class=&p&&))&/span& &span class=&n&&add&/span&&span class=&p&&(&/span&&span class=&kt&&int&/span& &span class=&n&&x&/span&&span class=&p&&){&/span&
&span class=&kt&&int&/span& &span class=&n&&add&/span&&span class=&p&&(&/span&&span class=&kt&&int&/span& &span class=&n&&y&/span&&span class=&p&&){&/span&&span class=&k&&return&/span& &span class=&n&&x&/span&&span class=&o&&+&/span&&span class=&n&&y&/span&&span class=&p&&;}&/span&
&span class=&k&&return&/span& &span class=&n&&add&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&span class=&n&&printf&/span&&span class=&p&&(&/span&&span class=&s&&&%d&/span&&span class=&se&&\n&/span&&span class=&s&&&&/span&&span class=&p&&,&/span& &span class=&n&&add&/span&&span class=&p&&(&/span&&span class=&mi&&2&/span&&span class=&p&&)(&/span&&span class=&mi&&3&/span&&span class=&p&&));&/span&
&span class=&k&&return&/span& &span class=&mi&&0&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&测试结果:&/p&&figure&&img data-rawheight=&72& src=&/50/v2-0a28b861ed191cfe5c91e_b.jpg& data-rawwidth=&145& class=&content_image& width=&145&&&/figure&&p&(当然typeof可以写在main的外面,这里只是为了方便)&/p&&p&这里定义的跟上一篇的add2函数的功能是一毛一样的,但是相对于上次的定义稍微清晰那么一点,毕竟不用辛苦地数返回类型了= =。(并不)&/p&&p&&br&&/p&&p&typeof()括号里还能放值:&/p&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&n&&typeof&/span&&span class=&p&&(&/span&&span class=&sc&&'a'&/span&&span class=&p&&)&/span& &span class=&n&&c&/span&&span class=&p&&;&/span&
&/code&&/pre&&/div&&p&相当于&/p&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&kt&&char&/span& &span class=&n&&c&/span&&span class=&p&&;&/span&
&/code&&/pre&&/div&&p&这个就比较厉害了。&/p&&p&typeof 、语句表达式
和宏一起弄,还可以弄出类型推导。(其实这点我也不是很清楚)&/p&&p&&br&&/p&&hr&&p&那么我们就利用这两个拓展,弄出一个Lambda表达式(功能不那么好的)&/p&&p&&br&&/p&&p&噢,稍微讲讲什么叫&a href=&/?target=https%3A//en.wikipedia.org/wiki/Lambda_calculus& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&lambda表达式&i class=&icon-external&&&/i&&/a&:&/p&&p&格式:&/p&&p&&img src=&/equation?tex=%3C%E8%A1%A8%E8%BE%BE%E5%BC%8F%3E%3A%3D%3C%E5%8F%98%E9%87%8F%3E& alt=&&表达式&:=&变量&& eeimg=&1&&&/p&&p&&img src=&/equation?tex=%3C%E8%A1%A8%E8%BE%BE%E5%BC%8F%3E%3A%3D%28%3C%E8%A1%A8%E8%BE%BE%E5%BC%8F%3E%3C%E8%A1%A8%E8%BE%BE%E5%BC%8F%3E%29& alt=&&表达式&:=(&表达式&&表达式&)& eeimg=&1&&&/p&&p&&img src=&/equation?tex=%3C%E8%A1%A8%E8%BE%BE%E5%BC%8F%3E%3A%3D%28%5Clambda+%E5%8F%98%E9%87%8F.%3C%E8%A1%A8%E8%BE%BE%E5%BC%8F%3E%29& alt=&&表达式&:=(\lambda 变量.&表达式&)& eeimg=&1&&&/p&&p&有两个法则:&/p&&p&β归约:代换调外层一个约束变量&/p&&p&例子: &img src=&/equation?tex=%5Cleft%28+%5Clambda+x.x%5E%7B2%7D+%5Cright%293%5Crightarrow+3%5E%7B2%7D+%3D+9& alt=&\left( \lambda x.x^{2} \right)3\rightarrow 3^{2} = 9& eeimg=&1&&&/p&&p&α变换:更换变量名表达式意义不变&/p&&p&例子: &img src=&/equation?tex=%5Cleft%28+%5Clambda+x.x%5E%7B2%7D+%5Cright%29%5Crightarrow+%5Cleft%28+%5Clambda+y.y%5E%7B2%7D+%5Cright%29& alt=&\left( \lambda x.x^{2} \right)\rightarrow \left( \lambda y.y^{2} \right)& eeimg=&1&&&/p&&p&……我们可以看看Haskell里的例子&/p&&div class=&highlight&&&pre&&code class=&language-haskell&&&span&&/span&&span class=&o&&&&/span&&span class=&p&&(&/span&&span class=&nf&&\&/span&&span class=&n&&x&/span& &span class=&ow&&-&&/span& &span class=&n&&x&/span&&span class=&o&&^&/span&&span class=&mi&&2&/span&&span class=&p&&)&/span& &span class=&mi&&2&/span&
&span class=&mi&&4&/span&
&/code&&/pre&&/div&&p&应用在列表上:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&map (\x -& x^2) [2,3,4,5]
[4,9,16,25]
&/code&&/pre&&/div&&p&(PS 对应数学定义 “\”,就是λ;“-&”,就是“.”)&/p&&p&(PS 在haskell里其实可以直接写成(^2))&/p&&p&&br&&/p&&p&我们怎么在C语言里面实现类似的功能呢?&/p&&p&我们先可以这样写:&/p&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&kt&&int&/span& &span class=&nf&&main&/span&&span class=&p&&(&/span&&span class=&kt&&void&/span&&span class=&p&&){&/span&
&span class=&kt&&int&/span& &span class=&n&&x&/span& &span class=&o&&=&/span& &span class=&p&&({&/span&&span class=&kt&&int&/span& &span class=&n&&trible&/span&&span class=&p&&(&/span&&span class=&kt&&int&/span& &span class=&n&&x&/span&&span class=&p&&){&/span&&span class=&k&&return&/span& &span class=&mi&&3&/span&&span class=&o&&*&/span&&span class=&n&&x&/span&&span class=&p&&;}&/span& &span class=&n&&trible&/span&&span class=&p&&;})(&/span&&span class=&mi&&3&/span&&span class=&p&&);&/span&
&span class=&n&&printf&/span&&span class=&p&&(&/span&&span class=&s&&&%d&/span&&span class=&se&&\n&/span&&span class=&s&&&&/span&&span class=&p&&,&/span& &span class=&n&&x&/span&&span class=&p&&);&/span&
&span class=&k&&return&/span& &span class=&mi&&0&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&figure&&img data-rawheight=&67& src=&/50/v2-0023eda4aa238a96d367b2c_b.jpg& data-rawwidth=&137& class=&content_image& width=&137&&&/figure&&p&我们可以对这一段代码进行抽象:&/p&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&p&&({&/span&&span class=&kt&&int&/span& &span class=&n&&trible&/span&&span class=&p&&(&/span&&span class=&kt&&int&/span& &span class=&n&&x&/span&&span class=&p&&){&/span&&span class=&k&&return&/span& &span class=&mi&&3&/span&&span class=&o&&*&/span&&span class=&n&&x&/span&&span class=&p&&;}&/span& &span class=&n&&trible&/span&&span class=&p&&;})&/span&
&/code&&/pre&&/div&&p&变成:&/p&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&p&&({&/span&
&span class=&n&&type&/span& &span class=&n&&name&/span& &span class=&n&&func_body&/span&
&span class=&n&&name&/span&&span class=&p&&;&/span&
&span class=&p&&})&/span&
&/code&&/pre&&/div&&p&用宏我们可以写成:&/p&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&cp&&#define Lambda(type,body) ({\&/span&
&span class=&cp&&
type lambda_funcname body\&/span&
&span class=&cp&&
lambda_ \&/span&
&span class=&cp&&})&/span&
&/code&&/pre&&/div&&p&&br&&/p&&p&测试下&/p&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&kt&&int&/span& &span class=&nf&&main&/span&&span class=&p&&(&/span&&span class=&kt&&void&/span&&span class=&p&&){&/span&
&span class=&kt&&int&/span& &span class=&n&&x&/span& &span class=&o&&=&/span& &span class=&n&&Lambda&/span&&span class=&p&&(&/span&&span class=&kt&&int&/span&&span class=&p&&,(&/span&&span class=&kt&&int&/span& &span class=&n&&x&/span&&span class=&p&&){&/span&&span class=&k&&return&/span& &span class=&mi&&3&/span&&span class=&o&&*&/span&&span class=&n&&x&/span&&span class=&p&&;})(&/span&&span class=&mi&&3&/span&&span class=&p&&);&/span&
&span class=&n&&printf&/span&&span class=&p&&(&/span&&span class=&s&&&%d&/span&&span class=&se&&\n&/span&&span class=&s&&&&/span&&span class=&p&&,&/span& &span class=&n&&x&/span&&span class=&p&&);&/span&
&span class=&k&&return&/span& &span class=&mi&&0&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&figure&&img data-rawheight=&97& src=&/50/v2-d203093cbb655d696d3c5e_b.jpg& data-rawwidth=&209& class=&content_image& width=&209&&&/figure&&p&&br&&/p&&p&但是,现在的功能还暂时不够完善,这就要用上typeof了:&/p&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&cp&&#define Lambda(return_type,func_body) ({\&/span&
&span class=&cp&&
typeof(return_type) lambda_funcname func_body\&/span&
&span class=&cp&&
lambda_ \&/span&
&span class=&cp&&})&/span&
&/code&&/pre&&/div&&p&于是乎,我们可以改写下上一篇的一些函数:&/p&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&kt&&int&/span& &span class=&p&&(&/span&&span class=&o&&*&/span&&span class=&p&&(&/span&&span class=&o&&*&/span&&span class=&n&&currying&/span&&span class=&p&&(&/span&&span class=&kt&&int&/span& &span class=&p&&(&/span&&span class=&o&&*&/span&&span class=&n&&f&/span&&span class=&p&&)(&/span&&span class=&kt&&int&/span&&span class=&p&&,&/span&&span class=&kt&&int&/span&&span class=&p&&)))(&/span&&span class=&kt&&int&/span&&span class=&p&&))(&/span&&span class=&kt&&int&/span&&span class=&p&&){&/span&
&span class=&k&&return&/span& &span class=&n&&Lambda&/span&&span class=&p&&(&/span&&span class=&kt&&int&/span& &span class=&p&&(&/span&&span class=&o&&*&/span&&span class=&p&&)(&/span&&span class=&kt&&int&/span&&span class=&p&&),(&/span&&span class=&kt&&int&/span& &span class=&n&&x&/span&&span class=&p&&){&/span&
&span class=&kt&&int&/span& &span class=&p&&(&/span&&span class=&o&&*&/span&&span class=&n&&f1&/span&&span class=&p&&)(&/span&&span class=&kt&&int&/span&&span class=&p&&,&/span&&span class=&kt&&int&/span&&span class=&p&&);&/span&
&span class=&n&&f1&/span&&span class=&o&&=&/span&&span class=&n&&f&/span&&span class=&p&&;&/span&
&span class=&k&&return&/span& &span class=&nf&&Lambda&/span&&span class=&p&&(&/span&&span class=&kt&&int&/span&&span class=&p&&,(&/span&&span class=&kt&&int&/span& &span class=&n&&y&/span&&span class=&p&&){&/span&
&span class=&k&&return&/span& &span class=&n&&f1&/span&&span class=&p&&(&/span&&span class=&n&&x&/span&&span class=&p&&,&/span&&span class=&n&&y&/span&&span class=&p&&);&/span&
&span class=&p&&});&/span&
&span class=&p&&});&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&测试下&/p&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&&span class=&kt&&int&/span& &span class=&nf&&main&/span&&span class=&p&&(&/span&&span class=&kt&&void&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&n&&printf&/span&&span class=&p&&(&/span&&span class=&s&&&%d&/span&&span class=&se&&\n&/span&&span class=&s&&&&/span&&span class=&p&&,&/span& &span class=&n&&currying&/span&&span class=&p&&(&/span&&span class=&n&&add&/span&&span class=&p&&)(&/span&&span class=&mi&&1&/span&&span class=&p&&)(&/span&&span class=&mi&&2&/span&&span class=&p&&));&/span&
&span class=&k&&return&/span& &span class=&mi&&0&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&figure&&img data-rawheight=&91& src=&/50/v2-6a6846dfe5a890debc811d53e08dd7a1_b.jpg& data-rawwidth=&167& class=&content_image& width=&167&&&/figure&&p&不过……代码的可读性并没有提高……反而更难读懂了= =(可能是我的锅)&/p&&p&不过建议就是,在Lambda函数体里最好要重新定义下要从外部捕获的变量,防止某些让人费解的bug出现。。。&/p&&p&&br&&/p&&p&你看,不用语句表达式,我们就没办法定义这样的lambda,应该,对吧?。&/p&&p&&br&&/p&&hr&&p&啥时候有兴致了,再尝试下其它东西(逃&/p&
上一篇…… 我们每个星期都有一节上机课,那时我才有时间鼓捣C语言。(捂脸,其实是因为懒……)正所谓乱搞出真知……我又接触了一点点GCC对C语言的一些语法扩展。看来又可以实现一些fp的一些功能了。(GCC真的强大……) 上…
&strong&这篇我已经答过一次了。那在这里就再回答一次吧。谁让我颜好任性。&br&&/strong&&br&&strong&新手养猫指南(咲&/strong&(xiao)&strong&手专稿)&/strong&&br&&br&接一只小猫回家,是一件非常非常幸运的事情。从此以后你就多了一个小孩子,也多了一个一生的伙伴。在决定养一只小猫之前,是要做好养它一辈子到寿终正寝的心理准备的。因为小猫一旦放养到野外,寿命最多只有2~3年,下场很凄惨。所以没做好准备可不能轻率养吖。当然猫这个从公元前2500年古埃及时期就被当做捕鼠卫士的神奇物种,也因为它生性温和,安静可爱的特点,带给了一批又一批的人们无尽的欢乐。&br&&br&下面就来讲一下一个养猫新手要做哪些准备!&br&&br&首先&strong&判断是大猫还是奶猫&/strong&。&strong& (&/strong&&a href=&/question//answer/& class=&internal&&怎样判断猫的年龄? - 咲手的回答&/a& )
&strong&&u&建议新手选择两个月以上的猫,能够自己吃猫粮自己排便的小猫进行喂养。&/u&&/strong&奶猫还是等自己有经验一些,或者紧急情况下才尝试喂养哦。&br&&br&选择好一只健康的猫。请往下看。&br&&img src=&/51ea59b266d0ed5a2e1a198d34f21ef7_b.jpg& data-rawheight=&465& data-rawwidth=&350& class=&content_image& width=&350&&&strong&一.接猫篇:&/strong&&br&&strong&1.健康检查。&/strong&在接一只猫咪回来之前,要先确认下猫咪是否健康,是否做了驱虫。&br&&strong&2.选用合适的接猫工具:&/strong&可以选择适当大小的宠物航空箱或者小铁笼(外面罩上透空气的布罩防止猫被陌生环境吓到)。对于大猫尽量不要用纸箱以防受惊半途逃走。&br&&strong&3.给猫一个安静自由的环境&/strong&。猫咪到家后不要急着去拥抱它或者亲它。有小孩子的家庭尤其要注意,先不让孩子去逗猫咪,猫咪是出了名的敏感和慢热的动物,为了防止猫咪受惊,尽量给它一个时间去熟悉新环境。建议先把小猫放在一个房间里不去打扰它。&br&&br&&strong&4.做好保护工作。&/strong&&br&小猫和小孩子一样,喜欢蹦蹦跳跳,蹭来蹭去。所以收起家中刀具,玻璃制品等易碎的东西,以及一切猫不能碰的东西:&br&&u&&b&巧克力,咖啡,百合花,各种药品,各种家庭用酸性碱性清洁剂(以防舔食),樟脑丸,杀虫剂,家具用亮光漆。&/b&&/u&&br&&br&&b&做好封窗(如何封窗这是一个坑我马上写)。&/b&有条件的家庭可以购买&b&&u&铁丝制的纱窗&/u&&/b&。因为猫咪喜欢看窗外,所以要防止猫咪因为在窗户上玩而不小心打开窗户掉下去(高层住户)或者溜出去的情况(一楼住户)。还有一个小技巧,每次打开窗户的时候不要让猫咪看到。因为有的机智的猫咪会偷偷学会怎么开窗户!所以这也是教给家长们一点必要的心机!!嘻嘻嘻!!&img data-rawwidth=&427& data-rawheight=&640& src=&/9ad7a7b7a4712caf046d76_b.jpg& class=&origin_image zh-lightbox-thumb& width=&427& data-original=&/9ad7a7b7a4712caf046d76_r.jpg&&&br&&u&&b&有的家长问猫发情了看着它心疼能不能把它放出家去玩。其实从后果来看这是很危险的。&/b&&/u&我见过很多因为发情溜出家去的猫,因为和其他猫占地盘打斗受伤,因为和其他野猫交配而受伤,即使回来了伤口也很深最后发炎的,还有因为追其他异性而迷路,或者因为吃了别人喂的有毒的东西而再也回不来的情况。因为家养猫长期不在野外生存,对于外界缺粮缺水,野猫的地盘都没有足够的适应力。所以出于负责任的态度,&u&&b&家长们要及时去做封窗和做绝育(绝育篇详细讲了怎么做绝育)&/b&&/u&&i&,&/i&让自己的猫咪不要呆在危险的境地里不自知。&br&&br&&br&&br&&strong&5.洗澡和驱虫。&/strong&&br&&strong&①洗澡。&/strong&对于这位家里的新成员要做一个健康检查。观察猫猫身上脏不脏,有没有跳蚤,有没有感冒着凉(尤其是家里有其他猫的家庭,更应该注意确认,新来的猫要确认没有猫瘟,猫癣鼻支,口炎等传染病再带回来哦)&br&3个月以内的小猫因为抵抗力比较低,尽量不要洗澡。3个月以上的猫猫,回家洗澡。如果洗澡要关好窗户。并且及时热风吹干。谨防感冒。&br&&br&&b&②驱虫。&/b&猫咪因为是全身覆盖毛的哺乳动物,会有体内外寄生虫的困扰。而寄生虫跑到人身上更是很头疼的。所以要及时的消灭它们。&br&&b&体外驱虫:德国产的福莱恩喷剂或者福莱恩滴剂&/b&(不要使用灭蚤项圈和灭蚤宁)。有效去除跳蚤。一喷跳蚤就会全跑出来。所以喷的时候要放在一个空旷干净滴地方。适用于8周龄以上所有犬猫品种。&br&&b&体内驱虫:拜耳公司的拜耳内虫逃(for cats)或者大宠爱。&/b&按说明,可消灭8种以上处于任何发展阶段的绦虫、蛔虫和蠕虫肠道体内寄生虫,消灭率超过99%。 蛔虫 (猫弓首蛔虫,狮弓蛔虫)
2种;钩虫 (猫钩虫,犬钩口线虫,巴西钩口线虫,狭头钩虫) 4种;绦虫 (犬复孔绦虫 ,巨颈绦虫) 2种。&br&&b&
用量: &/b&奶猫满6周,8周,10周和12周各吃一次。然后到六个月大之前每个月吃一次。&br&
六个月以上的猫猫,每3个月吃一次。&br&
一岁以上的猫猫,每半年吃一次。&br&
怀孕母猫不建议吃驱虫药。如果有需要。分娩前10天吃一次。哺乳结束后2周,4周各吃一次。&br&&br&&br&&strong&③疫苗:&/strong&在主子到了4个月大的时候带去做疫苗。避免主子得常见的猫瘟,鼻支等病。有些主子省钱不想打,但是对于小猫小狗来说,&strong&猫瘟和鼻支都是治愈率非常低的病。(&/strong&po主就救过一只狗瘟的狗,最后死的非常惨烈&strong&)&/strong&所以各位家长请记住,&strong&一分价钱一分货。不要为了省钱而牺牲小猫猫的安全。&/strong&&br&&img src=&/75b29dec577fe23fda2643d_b.jpg& data-rawwidth=&350& data-rawheight=&350& class=&content_image& width=&350&&&strong&二.装备篇:&/strong&&br&紧接着就要着手买一些东西了。在小猫咪到家之后,第一件事情就是赶紧准备吃喝拉撒的用具。第一步需要购买主子需要的物品。&br&&br&&strong&A.猫奶粉&/strong& (推荐KMR猫奶粉,羊奶粉,条件有限的喵喵家长可以购买婴儿奶粉1段,或者舒化奶),&strong&猫奶瓶,普通去掉针头的针筒&/strong&(一般宠物医院都可以买到),
非常重要!!&br&&br&&strong&B.猫粮和妙鲜包 ,猫罐,猫的食盆&/strong&
次级重要!!
&br&&br&首先说猫的食盆要准备两个。一个用来装水,另一个装吃的。如果家里养不止一只猫,要每只猫一个饭碗哦。&br&那么如何选择合适的猫粮呢。当然是推荐天然粮!小白会问啥是天然粮,贵不贵之类的问题。&strong&最低限度是买皇家的粮。晋级选择就很多了。now,go natural,渴望,wellness, EVO好多好多。以后会细讲。&/strong&不要买那些10块钱一斤的粮。里面的营养实在是太少了哦。谨记猫是肉食动物。咱们人吃的猪肉一斤还要13块钱呢。有的人因为贪便宜买了很次的粮,猫咪一个是吃不饱,另外一个是饭量也会变大。不但不省钱也会增加猫咪生病的危险。&br&&br&&strong&C.猫砂+猫砂盆&/strong&&br&&br&猫砂盆也是一只猫配备一个猫厕所。这是为了防止一只以上的猫共处一室的时候,互相嫌弃而乱拉。&br&现在市场上的猫砂也是应有尽有。可以根据需要选择。结团猫砂最容易买到。市场超市和宠物市场都有卖。注意不要买灰尘太大的,弄得猫咪一身灰最后弄脏猫猫也弄脏家里。&br&&br&&strong&D.旅行用品&/strong& :航空箱,铁笼子,软猫包(也十分重要!!!)&br&每一个主人都应该准备一个结实耐用的猫笼。猫笼的用处太大啦。比如家里来了客人或者小动物害怕猫咪受惊,或者需要带猫去做动物医院做绝育,或者需要过年回家送去寄养,用处太大啦。&br&&img src=&/bfbdbe4c060500_b.jpg& data-rawwidth=&541& data-rawheight=&432& class=&origin_image zh-lightbox-thumb& width=&541& data-original=&/bfbdbe4c060500_r.jpg&&&br&&strong&E.常备调理营养品&/strong&:妈咪爱(必备!!!!!),乳酶生,思密达,普通去掉针头的针筒(一般宠物医院都可以买到必备),复合维生素(可选),牛磺酸(可选)&br&&br&&strong&F.护理产品:猫的体内驱虫药(推荐拜耳牌内虫逃),体外驱虫药,猫眼药水,猫洗澡香波,猫的耳螨用药,猫牙刷、猫刷牙手套和猫牙膏,猫的口腔喷剂,喂药用的小针筒,猫指甲剪,化毛膏(推荐骏宝)和猫草,梳子。&/strong&&br&猫的各方面需要和人很像。基本上我们需要用的它们都要用。有的家长可能会忽视买化毛膏或者猫草,但是对于猫来说如果毛团吞进肚子又消化不了是很危险的。家长也不要忽视买猫牙膏,现在的猫又喜欢吃妙鲜包,牙齿上面长牙结石这种病也是要防治的,推荐用拇指手套每天给猫咪擦擦牙,如果猫猫长了牙结石一定要抓紧治疗,免得发展成牙龈炎症。&br&&br&&strong&G.猫玩具:&/strong&逗猫棒,小老鼠,猫薄荷,猫抓板&br&&br&&strong&H.奢侈级别:&/strong&猫窝,猫爬架。&br&在冬天的时候有一个温暖的猫窝很重要。因为担心猫猫会感冒。猫爬架就是见仁见智了,如果比较小的屋子,也可以让猫猫在衣柜这样的地方来回蹦跳。注意高度差不能太大,可以在衣柜旁边放一些高度适当的箱子。方便它来回玩耍。&br&&br&&strong&I.学者级别:&/strong&一些关于猫习性的书,关于猫的论坛(豆瓣爱猫俱乐部小组,网站猫咪有约)。&br&&br&&br&&strong&这里注意&/strong&:&strong&&u&ABC必买&/u&&/strong&。根据小猫的年龄,3个月内的猫咪,猫奶粉都要给喝。这样打下良好基础的小猫会非常非常的健壮。避免在成长期落下身体弱的毛病,防止以后生病。&br&&br&&br&&br&&br&&strong&三.喂养篇:&/strong&&br&猫咪是哺乳动物,但是却和人的饮食习惯不太一样。它们是肉食动物。而且还有很多不能吃的东西。&br&&img src=&/6b3def390f39979cdb0f683f606e9834_b.jpg& data-rawheight=&742& data-rawwidth=&1350& class=&origin_image zh-lightbox-thumb& width=&1350& data-original=&/6b3def390f39979cdb0f683f606e9834_r.jpg&&奶猫在成长过程中会经历三个时期。&br&&br&第一个时期是&strong&快速生长期。这个时候要吃幼猫粮。3个月内的猫猫最好还要添加猫奶粉。一天要吃5~6顿。&/strong&(吃了之后猫猫的毛发会亮亮的)2~6个月大的猫断奶后进入快速生长期。需要营养均衡、同时蛋白质及热量都较高的优质食物来满足身体生长的需要。小猫胃口小,嘴小,但是生长和消化的都是非常快的。幼猫必需食用经过特殊配方的优质幼猫猫粮。这类优质幼猫粮的特点是以肉类为主要的原料,同时非常容易消化,含有大量营养素,能满足幼猫的特殊营养需求。&br&&br&1个月大小的猫猫食物:羊奶粉+泡软猫粮。喂食频率:4小时一次。一天6顿。(奶不可以断太早。猫粮一次5~6粒)喂食量:酌情增加。浓度:一勺奶粉两勺温水。水温依然是温热。&br&&br&排泄:给小猫准备好猫砂盆。小猫现在就可以试着使用猫砂盆了。把它抱到猫砂盆里爪子划拉两下猫砂。它就会开始玩了。&br&&br&2个月大小的猫猫食物:泡软猫粮+羊奶粉 喂食频率:6小时1次。&strong&一天4顿以上。&/strong&(猫粮作为主粮,适当加入妙鲜包不要太多。羊奶粉每天喂一次。&br&排泄:会自己排便。&br&&br&3个月大小的猫猫食物:干猫粮+妙鲜包 偶尔羊奶粉
喂食频率:8小时一次,&strong&一天3顿以上。(&/strong&羊奶粉依然每天给一点)&br&&br&4个月及以上的猫猫食物:干猫粮+妙鲜包。喂食频率:&strong&早晚各一顿。&/strong&这个时候猫猫进入抽条和长身体的时期,还会渐渐从尖嘴猴腮变成大包子脸。每天喜欢吃就多给一顿。&br&&br&第二个时期是&strong&快速成熟期&/strong&。&strong&选择吃优质干猫粮+猫罐头&/strong&。&strong&早晚各一顿。还想吃的话就加一顿。&/strong&6个月以上的猫咪会走向性成熟。猫咪生长速度开始变慢,也没有原来那么好动。这时他们每餐的食量较大,所以可以减少每天用餐的次数。虽然这时猫的体型很像成猫,但是其实每天都会长大的!这个时期猫咪喜欢吃优质干猫粮,补加适当的罐头!&br&第三个时期是&strong&成猫期。这个时候吃的要换成成猫粮。&/strong&&strong&每天早晚各喂一次就可以了。&/strong&成猫不再需要幼猫粮所提供的大量热能和大量的营养素。换粮要按照宠物换粮法则,在5~7天内慢慢更换。室内的猫咪要注意肥胖的问题。可以准备一个&strong&体重秤&/strong&来监督猫猫(非常好用哦)。&br&&br&&br&&p&&strong&四.清洁篇&/strong&&/p&&strong&打扫:猫砂盆每天差不多要铲两次。早晚各一次。&/strong&当然勤奋如我也可以看到就去铲。屋子里也要经常通风打扫。主子一般都喜欢家里干干净净的。如果地面比较脏兮兮主子心情就会不好。所以每周家里有必要擦地。爱干净的家长也可以用84消毒液or杜邦卫可消毒液稀释后擦地。&br&&br&&br&&br&&br&&strong&洗护:&/strong&在炎热的夏天到来的时候可以给4个月及以上的主子洗个澡。毛毛洗的白白的主子自己也会很舒服。但是要注意保暖。平时家里温差和室外不能超过3度。平时如果看到主子有眼屎,或者挠耳朵的迹象,要擦拭干净然后滴眼药水和去耳螨的药。&br&&br&有的家长特别喜欢开空调,如果家里有了猫咪之后,空调开的温度和室外温差不能超过三度哦。因为随着温度降低和屋里气流流动速度变快,猫咪这种鼻子极度灵敏的生物,是会敏感感觉到的。所以一定要给它们一个适应过程。建议不要将冷风直吹猫咪,让冷风朝屋子上方吹,这样屋子温度会下降的比较均匀。同时有条件的家庭可以同时开加湿器,给猫咪一个舒适健康的环境。&br&&br&&br&&br&&strong&五.绝育篇&/strong&&br&&br&对于6个月左右的猫,进入了性成熟期。公猫会开始JJ经常勃起,夜里嚎叫,到处呲尿。母猫也有类似的举动。做为有责任感的主人,不要妇人之仁的舍不得给它们绝育。&strong&家养的猫咪如果发情得不到满足也是很可怜的。公猫JJ会充血得不到释放,母猫子宫分泌的液体还会倒流回子宫里面,引发子宫蓄脓等问题。&/strong&不然你作为一个成年人你试试,让你的JJ一直充血勃起再充血再勃起就是不能撸,是不是很残忍。&strong&而生下来的小猫也因为数量庞大而找不到领养,最后成为流浪猫,那样下场就很悲惨。&/strong&没办法这个人类社会就是这样。所以我们要力所能及的带他们去做绝育。&br&&br&猫在第一次发情过后就可以带去做绝育了。一般公猫8个月大,母猫7个月大就可以去做绝育。带去做绝育之前要确认猫的身体健康活泼。不然痊愈的就慢。&br&&br&公猫绝育需要做的是体检和麻醉,然后去除睾丸。费用大概是400左右。母猫需要去除子宫输卵管,因为要肚子上有刀口,所以费用比公猫的昂贵,现在北京价格大概是900左右。公猫母猫绝育后要带上伊丽莎白圈在笼子里静养,防止它们撕扯伤口。注意家里卫生环境的消毒防止伤口感染。公猫需要2~3天伤口就会痊愈。母猫需要7天~10天也就可以愈合了。&br&&br&&br&&b&六.留守猫咪和寄养篇&/b&&br&&br&当要出远门几天的话,猫咪怎么办。在大城市的养猫族里面有很多是一个人住。家人不在当地没法帮着照料宠物,朋友也没有场地或者时间。这时候有三个办法。&br&1.猫咪留守家中。如果出门1~2天,猫咪照顾自己是完全没有问题的。在家中多放几盆水。放足够量的猫粮。猫砂盆尽可能多放一两个。避免猫猫因为猫砂盆不干净而乱拉和叫。&br&&br&2.上门喂养。如果遇到节日或者出差,3天以上不在家。可以请钟点工,清洁阿姨,或者朋友至少每两天过来给换水添粮和铲屎(当然最好是每天都来啦)。现在市面上钟点工价格也还ok。当然还是要找信得过的人噢。(收好家中贵重物品)顺便帮忙通风换气。猫咪是很省事的宠物,不需要溜也不需要很多照顾。有条件的话还可以请朋友帮忙拍照片,随时看一下自己的猫咪的状态。&br&&br&3.宠物店寄养。&br&家长要出远门,或者家里有活动。只好把猫咪送去寄养。这种情况下,现在有很多宠物店都提供寄养服务。寄养的优点在于保证了猫咪的安全,不好一点在于猫咪生性怕生,要当心染上疾病或者导致抑郁。教大家一个窍门,送猫咪去寄养的时候也带上猫砂,猫玩具。一般寄养机构会懒得换猫砂。殊不知猫咪是很介意别的猫住过的气味的。所以要把猫砂换掉。同时挂上自己猫喜欢的猫玩具。让猫咪有一种熟悉感。&br&当然最好还是上门喂养。以避免寄养可能导致的传染病的危险哦。&br&&img data-rawwidth=&2448& data-rawheight=&3264& src=&/b4fc976a09c14c51f2d56e_b.jpg& class=&origin_image zh-lightbox-thumb& width=&2448& data-original=&/b4fc976a09c14c51f2d56e_r.jpg&&&br&&br&&br&&br&&strong&七. 医疗篇&/strong&&br&这里给大家分析一下几种常见猫猫的病治疗方法。均是亲身治疗后的分享。(不用同情本PO主)猫是一种非常坚强的猎人型生物。猫有病痛从来都是忍着不会表现出来。据说还有的病重猫会突然间离家出走,不想让主人看到自己死去的样子。既然养了这么高傲霸气的生物,我们作为主人就要拿出察言观色的本领来。&br&&br&猫咪生病表现1:精神不振躲起来&br&&br&很危险。当你回到家时,发现自己的爱猫并没有兴高采烈的来欢迎你,而是自己独自躲在窝里;当你拿出它最爱的玩具时,它并没有激动的扑上来;当你来到它身边轻轻的呼唤它时,它却不做任何反应……猫咪精神不振就是在告诉你,它病了。猫咪精神不振是很多病的前兆,当猫咪行动迟缓、性格内向、反应迟钝的时候一定要注意观察它的其他反应,以判断病情。&br&&br&猫咪生病表现2:鼻头干燥发热&br&&br&健康猫咪的鼻头是湿润冰凉的,除了猫咪睡觉和刚睡醒的时候,如果猫咪鼻头干燥的话说明猫咪身体不是很舒服。如果猫咪的鼻头除了干燥还发热的话,就要立即为猫咪测量体温,猫咪很可能已经发烧了。&br&&br&猫咪生病表现3:呼吸道异常&br& 猫咪出现呼吸道症状,如打喷嚏、咳嗽、呼吸困难等症状,可能是猫咪鼻支气管出现问题或者是感冒。&br&&br&猫咪生病表现4:呕吐&br& 呕吐也是猫咪生病的重要表现之一,主人要注意观察,如果呕吐后猫咪精神食欲都正常的话,一般仅仅是吐毛球,不用在意;如果持续呕吐则要禁食禁水24小时,喂乳酶生。如果禁食喂药后呕吐症状消失恢复正常,则应是误食导致小的肠胃炎,如果呕吐持续且加重则要立即就医。&br&&br&猫咪生病表现5:流口水&br& 当猫咪出现流口水或者嘴巴臭臭的症状时要注意观察猫咪的口腔,导致猫咪流口水的原因有食入异物(如鸡骨头、针等尖利物品)、口腔溃烂等,也有可能是老吃硬猫粮,缺乏维生素B导致的舌头冒泡。严重时可能会是猫白血病。&br&&br&猫咪生病表现6:跛行&br& 猫咪出现四肢不敢着地或者跛行的情况时,轻微的话可能是脚上扎刺,严重的话有可能是骨折。&br&&br&猫咪生病表现7:第三眼睑外露&br& 当猫咪睡觉时,如果你扒开它的眼皮可以看见眼球上附着着一层白色的膜,这层膜就叫做第三眼睑。当猫咪发烧或者身体严重虚弱时,就会露出第三眼睑。&br&&br&猫咪生病表现8:闭尿、尿频、尿失禁&br&一旦猫咪尤其是公猫泌尿系统出现问题,家长一定要立即重视起来,因为猫咪一旦憋尿超过24小时,就会引发氮血症甚至肾衰竭及尿毒症,后果是非常严重的。(po主我就中招过)猫咪泌尿道疾病如果治疗及时的话,猫咪能健康的生活,但是如果拖延病情,则会对猫咪的生命产生极大的威胁。&br&&br&&br&&strong&接下来说一下常见病症:&/strong&&br&&strong&NO1.猫癣&/strong&&br&猫癣担当就是我。请家长们戳: &b&&a href=&/question//answer/& class=&internal&&猫藓怎么治见效? - 咲手的回答&/a&&/b&&br&&br&&strong&NO2.拉肚子&/strong&&br&对于拉稀的猫咪来说,先要搞清楚他拉稀的原因。&br&A、消化不良 &br&这是最常见的拉稀的原因,尤其常见于半岁以下的小猫,单纯性的消化不良也叫溏便。&br&a1、换食物或者着凉&br&一般小猫会因为换食物就拉肚子。因为它们的系统很娇嫩,缺少好多消化酶,消化不好就会拉稀,要是不管就会越拉越稀,造成脱水,那会是很危险的。&br&还有一种就是着凉。一般来说只要猫咪的精神、食欲和平时没什么两样可以考虑是天气突然变化,着凉的原因导致拉稀的,要适当给猫咪保暖和调节他的消化。 &br&这两种情况下呢,要停止喂罐头和肉等不好消化的食物,一次喂两片乳酶生或者妈咪爱(多维乳菌散,药店可以买到,是给婴儿吃的。),但是不可以一起喂。用没有针头的针管就可以喂了。&br&&br&B、肠炎 &br&肠炎的症状是除了拉稀,猫咪的精神状态也不大好,体温升高。这种情况下猫咪的症状和猫传染性肠炎(猫瘟)非常相似,在确定猫咪已经免疫过之后可以按下面的方法治疗,否则请尽快去医院检查确诊。 &br&医生会给它服用一些消炎药。在服用消炎药后,需要给猫咪喂些活菌类的助消化药,如乳酶生、妈咪爱等,帮助猫咪恢复消化的能力。 还可以去药店买“思密达”给猫咪止泻,和庆大不同是是它是用物理的方法把细菌带出体外的。 &br&&br&C、寄生虫 &br&需要吃药打虫,最好先去医院做个便检,再针对性的用药。 一般来说3个月要吃一次体内驱虫药。&br&&br&&strong&猫猫肠胃不适的日常护理:&/strong&&br&1、注意饮食:不要喂食不宜消化的食物,保证饮水,切记不要喂生水,不要喂食过咸的食物。&br&2、注意猫咪生活环境的卫生和温度,如果条件允许的话,每天晒1——2个小时的太阳。&br&3、适当辅助一些有助消化的药物,比如干酵母片之类的,酵母片因为有淡淡的香味,猫猫会主动吃.而庆大则不能经常喂,时间长了,可能会导致听力下降。&br&&br&&strong&NO3 尿闭&/strong&&br&&strong&------------------又他么的下班了。----------------------------&/strong&
这篇我已经答过一次了。那在这里就再回答一次吧。谁让我颜好任性。
新手养猫指南(咲(xiao)手专稿) 接一只小猫回家,是一件非常非常幸运的事情。从此以后你就多了一个小孩子,也多了一个一生的伙伴。在决定养一只小猫之前,是要做好养它一辈子到寿终正寝…
&p&Node v6.3+ 的版本提供了两个用于调试的协议:&a href=&/?target=https%3A///buggerjs/bugger-v8-client/blob/master/PROTOCOL.md& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&v8 Debugger Protocol&i class=&icon-external&&&/i&&/a& 和 &a href=&/?target=https%3A//chromedevtools.github.io/debugger-protocol-viewer/v8/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&v8 Inspector Protocol&i class=&icon-external&&&/i&&/a& 可以使用第三方的 Client/IDE 等监测和介入 Node(v8) 运行过程,进行调试。&/p&&blockquote&&a href=&/?target=https%3A///buggerjs/bugger-v8-client/blob/master/PROTOCOL.md& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&v8 Debugger Protocol&i class=&icon-external&&&/i&&/a& 是 Node v6.3 之前的版本就支持的调试协议,使用一个 TCP 端口(通常是 5858)与Client/IDE 交互,之前比较流行的第三方调试工具 &a href=&/?target=https%3A///node-inspector/node-inspector& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&node-inspector&i class=&icon-external&&&/i&&/a& 就是基于这个协议。 &a href=&/?target=https%3A///node-inspector/node-inspector& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&node-inspector&i class=&icon-external&&&/i&&/a& 虽然名为 inspector,实际使用的是早期的 &a href=&/?target=https%3A///buggerjs/bugger-v8-client/blob/master/PROTOCOL.md& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&v8 Debugger Protocol&i class=&icon-external&&&/i&&/a& ,其工作原理如下:&br&1. 使用 node --debug=5858 yourScript.js 启动你的 js 脚本,则 node 在运行脚本时会将 5858 作为调试端口&br&2. 启动 node-inspector,它会开启一个后台进程,通过 8080 端口提供 http 服务。&br&3. 在浏览器中打开 &a href=&/?target=http%3A//127.0.0.1%3A8080/%3Fport%3D5858& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&127.0.0.1:8080/?&/span&&span class=&invisible&&port=5858&/span&&span class=&ellipsis&&&/span&&i class=&icon-external&&&/i&&/a& 则会连接到 node-inspector 后台进程,同时告诉后台连接使用 5858 作为调试端口的 node 进程。后台会提供一个类似于 chrome devtools 的 UI 调试界面。&/blockquote&&p&&a href=&/?target=https%3A//chromedevtools.github.io/debugger-protocol-viewer/v8/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&v8 Inspector Protocol&i class=&icon-external&&&/i&&/a&
是 node v6.3 新加入的调试协议,通过 websocket (通常使用 9229 端口)与 Client/IDE 交互,同时基于 Chrome/Chromium 浏览器的 devtools 提供了图形化的调试界面。&/p&&h2&&b&开启调试&/b&&/h2&&h2&&b&单进程&/b&&/h2&&p&使用 node --inspect=9229 yourScript.js 启动你的脚本,9229 是指定的端口号&/p&&h2&&b&多进程&/b&&/h2&&ol&&li&使用 child_process.fork() 开启子进程时可以传入 execArgv,使用 execArgv.push('--inspect=9229') 添加执行参数,开启子进程的调试端口。&/li&&li&在已经开启调试端口(以 9229 为例)的进程使用 cluster.fork() 克隆进程,新进程会自动开启调试,使用的端口在原进程的端口上递增(、9232)。&/li&&/ol&&h2&&b&调试工具接入&/b&&/h2&&h2&&b&chrome/chromium 浏览器&/b&&/h2&&p&chrome (v55+) 系的浏览器提供了三种接入调试方法&/p&&p&1) 使用控制台 node --inspect=9229 yourScript.js 启动脚本时控制台会输出用于打开调试界面的 URL ,复制到 chrome 中打开就可以了。&/p&&img src=&/50/v2-49ba8545cccc03b1fd1af1745cdaf8e4_b.jpg& dat}

我要回帖

更多关于 怎么向set里面存数据 的文章

更多推荐

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

点击添加站长微信