Lua学习个人笔记

1.1程序块:Lua执行的每段代码,例如一个源代码文件或者交互模式中输入的一行代码,都称为一个程序块

1.2注释:- - or --[[ --]]

1.3全局变量:无需声明,只需将值赋予一个全局变量就可以创建了。无需删除,若要删除直接赋值nil。

1.4解释器程序
选项参数“-e”可以直接在命令行中输入代码。
选项参数“-l”用于加载库文件。
选项参数“-i”表示在运行完其他命令行参数后进入交互模式
只要定义了一个名为“_PROMPT”的全局变量。解释器就会用它的值作为交互模式的命令提示符。例如
CXQ-MacBook-Pro:LUA-learn chenxiaoqiang$ lua -i -e "_PROMPT = 'lua>'"Lua 5.3.0 Copyright (C) 1994-2015 Lua.org, PUC-Rio
lua>//提示符

类型与值
Lua动态类型的语言。无类型定义的语法。
总共八种数据类型:nil表示“无效值”
boolean:true or false
number:表示的十实数

string字符串:Lua字符串是不可变的值。不能像C语言一样直接修改字符串的某个字符,而是应该根据修改要求来创建一个新的字符串。
a = “one string"
b= string.gsub(a, “one”, “anther")
“..”是Lua字符串连续操作符。数字后面记得先空格,不然会默认为小数点
例如:print(10 .. 20)
尽量不要使用这种强制转换。 而应该使用print(tostring(10)).

table:对象,永远是“匿名的”,一个持有table的变量与table自身之间没有固定的关联性。
lua>a = {}lua>k = "x"lua>a[k] = 100
lua>a[20] = "great"
lua>b=a
print(b[“x”]) —->100 等同于b.x

a = nil
b = nil
Lua中数组通常以1作为索引的起始值

Lua中长度操作符“#“用于返回一个数组或线性表的最后一个索引值(或为其大小)
— - 打印所有行

for i=1, #a do
print(a[i])
end
print(a[#a]) - -打印列表a的最后一个值
a[#a] = nil --删除最后一个值
a[#a+1] = v - -将v添加到列表末尾
user data(自定义类型),function,thread.
print(type(“hello world"))

表达式
table构造式
空构造式{}
days = {“Sunday”,”Monday”} days[1] = “Sunday”….
lua>polyline = {color = "blue", thickness = 2, npoints = 4,
{x=0,y=0},{x=-10,y=0}}
print(polyline[2].x) - - -10
构造式{x = 0, y = 0}相当于{[“x”]=0,[“y”]=0}
构造式{“r”,”g”,”b”}相当于{[1]= “r”,[2]=“g”,[3]=“b"}

语句
赋值:允许多重赋值,即一下子将多个值赋予多个变量
lua>a,b = 20,5*x
多重赋值:左边大于右边个数为nil, 反之则舍弃
局部变量:local语句来创建
局部变量只限于在块中使用。
一个块block:是一个控制结构的执行体,或者是一个函数的执行体再或者是一个程序块。
尽可能的使用局部变量是一种良好的编程风格

控制结构:
if then else end or elseif
while 条件 do
end
repeat-until 语句重复执行其循环体直到条件为真时结束。
在Lua中,一个声明在循环体中得局部变量的作用域包括了条件测试
数字型for : for var = exp1,exp2,exp3 do
end
var从exp1变化到exp2,每次步长为exp3。
如果不想有上限则使用math.huge
泛型for: 循环通过一个迭代器(iterator)函数来遍历所有值
打印a的所有值
for i,v in ipairs(a) do print(v) end
Lua的基础库提供了ipairs,这是一个用于遍历数组的迭代器函数。
i会被赋予一个索引值,v被赋予一个对应于索引值的数组元素值

函数
多重返回值:Lua允许函数返回多个结果
unpack函数。接受一个数组作为参数,并从下标1开始返回该数组的所有元素

function unpack(t,i)>> i = i or 1>> if t[i] then>> return t[i],unpack(t, i + 1)>> end

end

变长函数

function add(...)
local s = 0
for i,v in ipairs(...) do
s= s + v
end
return s
…表示函数可接受不同数量的实参

function fwrite(fmt, ...)>> return io.write(string.format(fmt, ...))>> end
fwrite("%d%d",4,5)
格式化文本string.format
一个函数在遍历其变长参数时只需使用表达式{…}。如果变长参数中包含一些故意传入的nil,那么此时就需要用函数select来访问变长参数了。调用select的时候必须传入一个固定参数selector和一系列变长参数。调用selector为数字N,那么select返回它的第n个可变实参;否则,selector只能为字符串”#“,这样select会返回变长参数的总数

具名实参

深入函数
在Lua中。函数是一种”“第一类值”,它们具有特定的词法域
第一类值:表示在Lua中函数与其他传统的类型的值(例如数字和字符串)具有相同的权利。函数可以存储到变量中无论是全局或者是局部。或table中,可以作为实参传递给其他函数,还可以作为其他函数的返回值
词法域:一个函数可以嵌套在另一个函数中,内部的函数可以访问外部函数中的变量。

函数与所有其他值一样都是匿名的。即它们都没有名称。当讨论一个函数名时(例如print),实际上是在讨论一个持有某函数的变量。这与其他变量持有各种值是一个道理。

a = {p = print}
a.p("hello")
hello
function foo (x) return 2x end
等同于 foo = function (x) 2
x end
一个函数定义实际就是一条语句。

闭合函数closure

function sortgrade(names,grades) table.sort(names, function(n1,n2)>> return grades[n1] > grades[n2]>> end)

end
grades称为“非局部的变量”。既不是全局也不是局部。但sort中得匿名函数却可以访问
function newCounter()>> local i = 0>> return function()>> i = i + 1>> return i>> end
end
c1 = newCounter()
c2 = newCounter()
一个closure就是一个函数加上该函数所需访问的所有“非局部的变量”。如果再次调用newCounter,那么它会创建一个新的局部变量i,从而得到一个新的closure.
closure对于回调函数也很有用。

非全局的函数

Lib = {}> Lib.foo = function (x,y) return x+y end
Lib.goo = function (x,y) return xy end
上下实现是相同的
function Lib.foo (x,y) return x+y end
function Lib.goo (x,y) return x
y end
定义递归的局部函数时,有特别需要注意的地方。先定义一个局部变量,然后再定义函数本身
local fact
fact = function(n) - - 若是local fact = function(n)会有错误,定义未完毕
if n == 0 then return 1
else return n*fact(n-1)
end
end
正确地尾调用
Lua支持“尾调用消除”:尾调用(tail call)就是一种类似于goto的函数调用。当一个函数调用是另一个函数的最后一个动作时,该调用才算是一条“尾调用”。举例:
function f(x) return g(x) end
也就是说当f调用完g后就再无其他事情可做了。(尾调用不消耗栈空间)
不符合尾调用的一些情况
return g(x) + 1 必须做一次加法
return x or g(x)
return (g(x)) 必须调整为一个返回值
在Lua 中,只有return <func>(<args>)这样的调用形式才算是一条尾调用

尾调用的一大应用就是编写“状态机”。这种程序通常以一个函数来表示一个的状态,改变状态就是goto到另一个特定的函数。

迭代器与泛型for
迭代器与closure
迭代器:就是一种可以遍历一种集合中所有元素的机制。在Lua中通常将迭代器表示为函数,每调用一次函数,即返回集合中的“下一个”元素
一个closure结构通常涉及到两个函数:closure本身和一个用于创建该closure的工厂函数。
例子:

function values(t)>> local i = 0>> return function () i = i+1; return t[i] end>> end> t = {10,20,30}> iter = values(t)> while true do>> local element = iter()>> if element == nil then break end>> print(element)

end
泛型for
for element in values(t) do>> print(element)
end
i = i + 1>> return i>> end
>> end
> c1 = newCounter()
> c2 = newCounter()
一个closure就是一个函数加上该函数所需访问的所有“非局部的变量”。如果再次调用newCounter,那么它会创建一个新的局部变量i,从而得到一个新的closure.
closure对于回调函数也很有用。

非全局的函数
> Lib = {}> Lib.foo = function (x,y) return x+y end
> Lib.goo = function (x,y) return xy end
上下实现是相同的
> function Lib.foo (x,y) return x+y end
> function Lib.goo (x,y) return x
y end
定义递归的局部函数时,有特别需要注意的地方。先定义一个局部变量,然后再定义函数本身
local fact
fact = function(n) - - 若是local fact = function(n)会有错误,定义未完毕
if n == 0 then return 1
else return n*fact(n-1)
end
end
正确地尾调用
Lua支持“尾调用消除”:尾调用(tail call)就是一种类似于goto的函数调用。当一个函数调用是另一个函数的最后一个动作时,该调用才算是一条“尾调用”。举例:
function f(x) return g(x) end
也就是说当f调用完g后就再无其他事情可做了。(尾调用不消耗栈空间)
不符合尾调用的一些情况
return g(x) + 1 必须做一次加法
return x or g(x)
return (g(x)) 必须调整为一个返回值
在Lua 中,只有return <func>(<args>)这样的调用形式才算是一条尾调用

尾调用的一大应用就是编写“状态机”。这种程序通常以一个函数来表示一个的状态,改变状态就是goto到另一个特定的函数。

迭代器与泛型for
迭代器与closure
迭代器:就是一种可以遍历一种集合中所有元素的机制。在Lua中通常将迭代器表示为函数,每调用一次函数,即返回集合中的“下一个”元素
一个closure结构通常涉及到两个函数:closure本身和一个用于创建该closure的工厂函数。
例子:
> function values(t)>> local i = 0>> return function () i = i+1; return t[i] end>> end> t = {10,20,30}> iter = values(t)> while true do>> local element = iter()>> if element == nil then break end>> print(element)
>> end
泛型for
> for element in values(t) do>> print(element)
>> end
泛型for的语法:for <var-list> in <exp-list> do
<body>
end
其中<var-list>是一个或多个变量名的列表,以逗号分隔;<exp-list>是一个或多个表达式的列表,同样以逗号分隔。通常表达式列表只有一个元素,即对迭代器工厂的调用。例如
for k,v in pairs(t) do print(k,v) end
变量列表的第一元素称为“控制变量”。在循环过程中该值绝不会是nil
for做的第一件事就是对in后面的表达式求值。这些表达式应该返回3个值供for保存:
迭代器函数、恒定状态和控制变量 的初值。这里类似于多重赋值,即只有最后一个表达式才会产生多个结果,并且只会保留前3个值,多余的值会被丢弃;而不足的话将以nil补足。

无状态的迭代器
就是一种自身不保存任何状态的迭代器。因此,我们可以在多个循环中使用同一个无状态的迭代器,避免创建新的closure开销。
在每次迭代中,for循环都会用恒定状态和控制变量来调用迭代器函数,一个无状态的迭代器可以根据这两个值来为下次迭代生成一个元素。例如ipairs。

具有复杂状态的迭代器

local iterator> function allwords()>> local state = {line = io.read(), pos = 1}>> return iterator, state>> end> function iterator(state)>> while state.line do>> local s,e = string.find(state.line, "%w+", state.pos)>> if s then>> state.pos = e + 1>> return string.sub(state.line, s, e)>> else>> state.line = io.read()>> state.pos = 1>> end>> end>> return nil

end

协同程序
概念:协同程序与线程差不多,也就是一条执行序列,拥有自己独立的栈、局部变量和指令指针,同时又与其他系统程序共享全局变量和其他大部分的东西。
一个具有多个协同程序的程序在任意时刻只能运行一个协同程序。并且正在运行的协同程序只会在其显式地要求挂起时,它的执行才会暂停。

1.基础知识:
协同程序的函数放置在一个名为“coroutine”的table中。
四个状态:挂起、运行、死亡、正常。
coroutine.create() coroutine.resume() coroutine.status() coroutine.yield()
协同程序的真正强大之处在于函数yield的使用上,该函数可以让一个运行中的协同程序挂起,而之后可以再恢复它的运行。
Lua>co = coroutine.create(function ()>> for i=1,10 do>> print("co",i)>> coroutine.yield()>> end

end)
在resume,并没有对应的yield在等待它,因此所有传递给resume的额外参数都将视为协同程序的主函数的参数。
Lua>co = coroutine.create(function (a,b,c) print("co",a,b,c) end)
Lua>return coroutine.resume(co,1,2,3)
在resume调用返回的内容中,第一个值为true则表示没错,而后面所有的值都是对yield传入的参数:
Lua>co = coroutine.create(function (a,b)>> coroutine.yield(a+b,a-b)>> end)
Lua>coroutine.resume(co,10,9)
与此对应的是,yield的返回的额外值就是对应resume传入的参数:
print("co",coroutine.yield())
end)
return iterator, state>> end> function iterator(state)>> while state.line do>> local s,e = string.find(state.line, "%w+", state.pos)>> if s then>> state.pos = e + 1>> return string.sub(state.line, s, e)>> else>> state.line = io.read()>> state.pos = 1>> end>> end>> return nil
>> end

协同程序
概念:协同程序与线程差不多,也就是一条执行序列,拥有自己独立的栈、局部变量和指令指针,同时又与其他系统程序共享全局变量和其他大部分的东西。
一个具有多个协同程序的程序在任意时刻只能运行一个协同程序。并且正在运行的协同程序只会在其显式地要求挂起时,它的执行才会暂停。

1.基础知识:
协同程序的函数放置在一个名为“coroutine”的table中。
四个状态:挂起、运行、死亡、正常。
coroutine.create() coroutine.resume() coroutine.status() coroutine.yield()
协同程序的真正强大之处在于函数yield的使用上,该函数可以让一个运行中的协同程序挂起,而之后可以再恢复它的运行。
Lua>co = coroutine.create(function ()>> for i=1,10 do>> print("co",i)>> coroutine.yield()>> end
>> end)
在resume,并没有对应的yield在等待它,因此所有传递给resume的额外参数都将视为协同程序的主函数的参数。
Lua>co = coroutine.create(function (a,b,c) print("co",a,b,c) end)
Lua>return coroutine.resume(co,1,2,3)
在resume调用返回的内容中,第一个值为true则表示没错,而后面所有的值都是对yield传入的参数:
Lua>co = coroutine.create(function (a,b)>> coroutine.yield(a+b,a-b)>> end)
Lua>coroutine.resume(co,10,9)
与此对应的是,yield的返回的额外值就是对应resume传入的参数:
>> print("co",coroutine.yield())
>> end)
Lua>coroutine.resume(co)trueLua>return coroutine.resume(co,1,2)
co 1 2
最后,当一个协同程序结束时,它的主函数所返回的值都将作为对应resume的返回值。
Lua>co = coroutine.create(function()>> return 6,7>> end)
Lua>print(coroutine.resume(co))
true 6 7

  1. 管道(pipe)与过滤器(filter)
    协同程序经典案例“生产者-消费者”
    Lua>function receive(prod)>> local status, value = coroutine.resume(prod)>> return value>> endLua>function send(x)>> coroutine.yield(x)>> endLua>function producer()>> return coroutine.create(function ()>> while true do>> local x = io.read()>> send(x)>> end>> end)>> endLua>function filter(prod)>> return coroutine.create(function()>> for line = 1, math.huge do>> local x = receive(prod)>> x = string.format(%5d %s",line,x)stdin:5: unexpected symbol near '%'
    Lua>function filter(prod)
    return coroutine.create(function()
    for line = 1, math.huge do
    local x = receive(prod)
    x = string.format("%5d %s",line,x)
  send(x)>>     end>>  end)>> endLua>function consumer (prod)>>    while true do>>      local x = receive(prod)>>      io.write(x, "\n")>>    end>> endLua>p = producer()Lua>f = filter(p)

Lua>consumer(f)

以协同程序实现迭代器
非抢占式的多线程

数据结构
1.数组
a = {} 新建
for i=1, 1000 do a[i] = 0
end

mt = {}

for i=1,N do mt[i] = {} --创建一个新行 for j=1,M do mt[i][j] = 0 end
Lua中table是一种对象,因此在创建矩阵时,必须显示地创建每一行。

元表(metatable)与元方法(meatmethod)

通常,Lua中得每个值都有一套预定义的操作集合。例如,数字相加,连接字符串。但是无法相加两个table,无法对函数比较,也无法调用一个字符串。
可以通过元表来修改一个值得行为,使其在面对一个非预定义的操作时执行一个指定的操作。
例如定义如何相加table的表达式。
Lua试图相加两个table时,它会先检查两者之一是否有元表,然后检查该元表中是否有一个叫_add的字段。如果Lua找到了该字段,就调用该字段对应的值。这个值也就是所谓的“元方法”,它应该是一个函数。
Lua中得每个值都有一个元表。Lua在创建新的table时不会创建元表:
t = {} print(getmetatable(t)) - - nil

使用setmetatable来设置或修改任何table的元表:

t = {}
t1 = {}
setmetatable(t, t1)
assert(getmetatable(t) == t1)

任何table都可以作为任何值的元表,而一组相关的table也可以共享一个通用的元表,此元表描述了它们的共同行为,一个table甚至可以作为它自己的元表,用于描述其特有的行为。
在Lua中只能设置table的元表。其他需要通过C代码来完成。

算术类的元方法
Set = {}
local mt = {}
function Set.new(l)
local set = {}
setmetatable(set, mt)
for _,v in ipairs(l) do
set[v] = true
end
return set
end

function Set.union(a,b)
local res = Set.new{}
for k in pairs(a) do
res[k] = true
end
for k in pairs(b) do
res[k] = true
end
return res
end

function Set.intersection (a,b)
local res = Set.new{}
for k in pairs(a) do
res[k] = b[k]
end
return res
end

function Set.tostring(set)
local l = {}
for e in pairs(set) do
l[#l + 1] = e
end
return "{" .. table.concat(l, ", ") .. "}"
end
function Set.print(s)
print(Set.tostring(s))
end

s1 = Set.new{10,20,30,40}
s2 = Set.new{30,1}

mt.__add = Set.union
s3 = s1 + s2
Set.print(s3)
mt.__mul = Set.intersection
Set.print((s1+s2)*s1)
如果想要清楚得到错误信息,则必须在实际操作前显示地检查操作数的类型
关系类的元方法
table访问的元方法
有两种可以改变table的行为:查询table及修改table中不存在的字段
_ _index元方法:如果有此方法当访问查询不到的时候会调用此方法(继承)table的更新
元方法可以是函数也可以是另一个table
_ newindex:用于table的更新。功能相似
两者的组合可以实现Lua的一些强大的功能:只读的table,默认值的table和面向对象编程
1.默认值的table
function setDefault (t,d)
local mt = {
_index = function () return d end}
setmetatable(t,mt)
end

环境
Lua将其所有的全局变量保存在一个常规的table中,这个table称为“环境(environment)”
优点:其一,不需要再为全局变量创造一种新的数据结构,因此简化了Lua的内部实习。另外一个优点是,可以像其他table一样操作这个table。
为了便于实时这种操作,Lua将环境table自身保存在一个全局变量_G中。以下代码打印当前环境所有全局变量的名称:
for n in pairs(_G) do print(n) end
全局变量声明:

value = _G["varname"]> valuex> _G["test"] = value
test
非全局的环境
setfenv(1,{})将当前环境改为一个新的空table
1表示当前函数,2表示调用当前函数的函数
模块与包
1.require函数
即使知道某些用到的模块可能已经加载了,但只要用到require就是一个良好的编程习惯。
2.编写模块的基本方法
最简单的方法:创建一个table
3.使用环境
创建模块的基本方法的缺陷在于,它要求程序员投入一些额外的关注。当访问同一模块中的其他公共实体时,必须限定其名称。并且,只要一个函数的状态从私有变为公有(反之也可),就必须修改调用。
函数环境可以解决上述创建模块时遇到的问题

面向对象编程
Lua的table是一种对象,首先:table与对象一样可以拥有状态,其次,table也与对象一样拥有一个独立于其值得标识(一个self)。最后table与对象一样具有独立于创建者和创建地的生命周期。
self的使用

Account = {balance = 0}> function Account.withdraw(v)>> Account.balance = Account.balance - v>> end
Account.withdraw(100.0)
Account = nil
a.withdraw(0) --错误
通过一个额外的参数self or this修改。
Account = {balance = 0}> function Account.withdraw(self,v)>> self.balance = self.balance - v>> return self.balance>> end
a = Account
return a.withdraw(a,100)
在Lua中。只需要使用冒号,就可以隐藏self参数
function Account:withdraw(v)>> self.balance = self.balance - v

end
a = Account
Account = nil
return a:withdraw(100)
1.类:
在Lua中实现原型很简单,使用继承即可。更准确地说,如果有两个对象a和b,要让b作为a的一个原型,只需输入下面语句
setmetable(a,__index = b)
在此之后,a就会在b中查找所有它没有的操作,若将b称为是对象a的类,只不过是术语上的一个变化而已。
Account = {balance = 0}
function Account:new(o)
o = o or {} setmetatable(o,self) self.__index = self
return o
end
当调用Account:new的时候,self就等于Account
2.继承
由于类也是对象,它们也可以从其他类获得方法。这种行为就是一种继承,可以很容易地在Lua中。
Account = {balance = 0}
function Account:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end

function Account:withdraw(v)
if self.balance < v then print("insufficient funds") end
self.balance = self.balance - v
end
function Account:deposit(v)
self.balance = self.balance + v
end
--派生子类使得账户可以透支
SpecialAccount = Account:new()
s = SpecialAccount:new{limit = 1000.0}
function SpecialAccount:withdraw(v)
if v - self.balance >= self:getLimit() then
print("insufficient funds")
end
self.balance = self.balance - v
end

function SpecialAccount:getLimit()
return self.limit or 0
end

test = SpecialAccount:new()
test:withdraw(500)
print(test.balance)

3.多重继承

弱引用table
三种方式:弱引用table,弱引用key,弱引用两者
一个table的弱引用类型是通过其元表中得—mode字段来决定的。这个字段的值应为一个字符串,如果这个字符串包含字母’k’,那么这个table的key是弱引用;如果这个字符串包含字母’v’,那么这个table是value的弱引用,

a = {}b= {__mode = "k"}setmetatable(a,b) --'a'为key的弱引用key = {}a[key] = 1key = {}a[key] = 2collectgarbage()for k,v in pairs(a) do print(v)
end
备忘录
local results = {}
setmetateble(results,{__mode = "v"})function createRGB(r,g,b) local key = r .. "-" .. g "-" .. b local color = results(key) if color == nil then color = {red = r, green = g, blue = b} results[key] = color end return color
end

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,757评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,478评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,540评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,593评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,903评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,329评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,659评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,383评论 0 195
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,055评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,337评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,864评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,227评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,820评论 3 231
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,999评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,750评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,365评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,260评论 2 258

推荐阅读更多精彩内容

  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,189评论 0 17
  • 你我皆普通 无太多峥嵘 生命数十载 一如穿堂风 从最初 天马行空 到后来 万物皆空 成长的归途 每迈出一步 都伴随...
    敏敏L_7495阅读 121评论 0 0
  • 路还长,天总会亮! 2016年12月2日,我又多了一个身份——母亲。 这一个月过的云里雾里,不算安稳。 在新年到来...
    RabbitLiRL阅读 430评论 0 3
  • 2017年7月14日晚,王女士到顺义公安分局后沙峪派出所报案,称被男友“周某”骗取钱财共计人民币90余万元。但经民...
    丁舒士阅读 223评论 0 0
  • 我就这样看着自己 一半清醒一半沉睡 早已麻木又渐次苏醒的内心 理想 再次席卷了大脑 我没有力气再和它计较 都治不了...
    诗海棠阅读 318评论 0 3