class, module, coroutine, begining error
+ some correction and addition.
This commit is contained in:
parent
655ce78eee
commit
74b02df3c1
217
README.md
217
README.md
@ -1,6 +1,7 @@
|
||||
# cheat-sheet-lua
|
||||
|
||||
Here is the IO-Project cheat sheet to quickly learn the "Lua" programming language
|
||||
Here is the IO-Project cheat sheet to quickly learn the "Lua" programming language.
|
||||
I suggest you to consult the documentation of lua for more information on the language, it is available by following [this link](https://www.lua.org/manual/5.3/).
|
||||
|
||||
## Table of contents
|
||||
|
||||
@ -8,7 +9,7 @@ Use this table of contents to travel more easily through this cheat sheet.
|
||||
|
||||
- [cheat-sheet-lua](#cheat-sheet-lua)
|
||||
- [Table of contents](#table-of-contents)
|
||||
- [The basics](#the-basics)
|
||||
- [Basics](#basics)
|
||||
- [Code comments](#code-comments)
|
||||
- [Variables and loop](#variables-and-loop)
|
||||
- [Functions](#functions)
|
||||
@ -16,8 +17,13 @@ Use this table of contents to travel more easily through this cheat sheet.
|
||||
- [Tables, Array, dict..](#tables-array-dict)
|
||||
- [Metatables and metamethods](#metatables-and-metamethods)
|
||||
- [Class-like tables and inheritance.](#class-like-tables-and-inheritance)
|
||||
- [Coroutine](#coroutine)
|
||||
- [Error handling](#error-handling)
|
||||
- [Modules](#modules)
|
||||
|
||||
## The basics
|
||||
## Basics
|
||||
|
||||
> We'll now introduce the basics of lua, starting with comments, variables, loops and functions.
|
||||
|
||||
### Code comments
|
||||
|
||||
@ -163,14 +169,13 @@ print 'hello' -- Works fine.
|
||||
|
||||
## Advanced
|
||||
|
||||
> Let's move on to more advanced notions. With the notion of table, class, module, coroutine, meta-programming and module.
|
||||
|
||||
### Tables, Array, dict..
|
||||
|
||||
````lua
|
||||
-- Tables = Lua's only compound data structure;
|
||||
-- they are associative arrays.
|
||||
-- Similar to php arrays or js objects, they are
|
||||
-- hash-lookup dicts that can also be used as lists.
|
||||
Tables are the only compound data structure in Lua, they are associative arrays. Similar to php arrays or js objects, they are hash-lookup dicts that can also be used as lists.
|
||||
|
||||
````lua
|
||||
-- Using tables as dictionaries / maps:
|
||||
|
||||
-- Dict literals have string keys by default:
|
||||
@ -218,11 +223,9 @@ end
|
||||
|
||||
#### Metatables and metamethods
|
||||
|
||||
````lua
|
||||
-- A table can have a metatable that gives the table
|
||||
-- operator-overloadish behavior. Later we'll see
|
||||
-- how metatables support js-prototypey behavior.
|
||||
A table can have a metatable that gives the table operator-overloadish behavior. Later we'll see how metatables support js-prototypey behavior.
|
||||
|
||||
````lua
|
||||
f1 = {a = 1, b = 2} -- Represents the fraction a/b.
|
||||
f2 = {a = 2, b = 3}
|
||||
|
||||
@ -283,3 +286,193 @@ eatenBy = myFavs.animal -- works! thanks, metatable
|
||||
````
|
||||
|
||||
#### Class-like tables and inheritance.
|
||||
|
||||
Classes aren't built in, there are different ways to emulate them with tables and metatables.
|
||||
The different ways to define a class in Lua are not easy to understand, so I suggest you to look at the [following document](support/class.lua) implementing 3 types of class definition. The last one being the one I chose (my preferred method).
|
||||
|
||||
````lua
|
||||
-- Explanation for this example is below it.
|
||||
Dog = {} -- 1.
|
||||
|
||||
function Dog:new() -- 2.
|
||||
newObj = {sound = 'woof'} -- 3.
|
||||
self.__index = self -- 4.
|
||||
return setmetatable(newObj, self) -- 5.
|
||||
end
|
||||
|
||||
function Dog:makeSound() -- 6.
|
||||
print('I say ' .. self.sound)
|
||||
end
|
||||
|
||||
mrDog = Dog:new() -- 7.
|
||||
mrDog:makeSound() -- 'I say woof' -- 8.
|
||||
|
||||
-- 1. Dog acts like a class; it's really a table.
|
||||
-- 2. function tablename:fn(...) is the same as
|
||||
-- function tablename.fn(self, ...)
|
||||
-- The : just adds a first arg called self.
|
||||
-- Read 7 & 8 below for how self gets its value.
|
||||
-- 3. newObj will be an instance of class Dog.
|
||||
-- 4. self = the class being instantiated. Often
|
||||
-- self = Dog, but inheritance can change it.
|
||||
-- newObj gets self's functions when we set both
|
||||
-- newObj's metatable and self's __index to self.
|
||||
-- 5. Reminder: setmetatable returns its first arg.
|
||||
-- 6. The : works as in 2, but this time we expect
|
||||
-- self to be an instance instead of a class.
|
||||
-- 7. Same as Dog.new(Dog), so self = Dog in new().
|
||||
-- 8. Same as mrDog.makeSound(mrDog); self = mrDog.
|
||||
|
||||
----------------------------------------------------
|
||||
|
||||
-- Inheritance example:
|
||||
LoudDog = Dog:new() -- 1.
|
||||
|
||||
function LoudDog:makeSound()
|
||||
s = self.sound .. ' ' -- 2.
|
||||
print(s .. s .. s)
|
||||
end
|
||||
|
||||
seymour = LoudDog:new() -- 3.
|
||||
seymour:makeSound() -- 'woof woof woof' -- 4.
|
||||
|
||||
-- 1. LoudDog gets Dog's methods and variables.
|
||||
-- 2. self has a 'sound' key from new(), see 3.
|
||||
-- 3. Same as LoudDog.new(LoudDog), and converted to
|
||||
-- Dog.new(LoudDog) as LoudDog has no 'new' key,
|
||||
-- but does have __index = Dog on its metatable.
|
||||
-- Result: seymour's metatable is LoudDog, and
|
||||
-- LoudDog.__index = LoudDog. So seymour.key will
|
||||
-- = seymour.key, LoudDog.key, Dog.key, whichever
|
||||
-- table is the first with the given key.
|
||||
-- 4. The 'makeSound' key is found in LoudDog; this
|
||||
-- is the same as LoudDog.makeSound(seymour).
|
||||
|
||||
-- If needed, a subclass's new() is like the base's:
|
||||
function LoudDog:new()
|
||||
newObj = {}
|
||||
-- set up newObj
|
||||
self.__index = self
|
||||
return setmetatable(newObj, self)
|
||||
end
|
||||
````
|
||||
|
||||
### Coroutine
|
||||
|
||||
Let's turn now to coroutines. Coroutines are functions that can be suspended and resumed at a later time. They are used to implement iterators, generators and event loops and represent a line of execution with its own stack. In other words, they can be compared to threads.
|
||||
|
||||
````lua
|
||||
-- Create a coroutine that prints 'Hello' and then stops.
|
||||
coHi = coroutine.create(function () print('Hello') end)
|
||||
print(coHi) -- thread: 0x7f9c0c00a0c0
|
||||
|
||||
-- Coroutine status can be 'suspended', 'running' or 'dead'.
|
||||
-- The coroutine is created in the 'suspended' state.
|
||||
|
||||
-- Resume the coroutine. It will print 'Hello' and stop.
|
||||
coroutine.resume(coHi) -- return 'true'
|
||||
print(coroutine.status(coHi)) -- 'dead'
|
||||
|
||||
-- We can also pass arguments to the coroutine.
|
||||
-- The arguments of the first resume are passed to the
|
||||
-- function of the coroutine. The following arguments
|
||||
-- are passed to the yield function.
|
||||
routine = coroutine.create(function (a, b, c)
|
||||
print('first print: ', a, b, c)
|
||||
print('yield1: ', coroutine.yield())
|
||||
print('yield2: ', coroutine.yield('a variable'))
|
||||
return(a+b+c)
|
||||
end)
|
||||
|
||||
-- will run the coroutine until the first yield.
|
||||
coroutine.resume(routine, 1, 2, 3)
|
||||
-- run the coroutine until the second yield passing
|
||||
-- the arguments 4, 5 and 6 to the 1er yield and
|
||||
-- retrieve the return value of the second yield.
|
||||
print('out routine: ' , coroutine.resume(routine, 4, 5, 6))
|
||||
-- this will run out the second yield and made the
|
||||
-- adition of 'a+b+c' and kill the coroutine.
|
||||
print(coroutine.resume(routine, 7, 8, 9)) -- 1+2+3 = '6'
|
||||
|
||||
-- All these steps will print:
|
||||
--[[
|
||||
first print: 1 2 3
|
||||
yield1: 4 5 6
|
||||
out routine: true a variable
|
||||
yield2: 7 8 9
|
||||
true 6
|
||||
--]]
|
||||
````
|
||||
|
||||
### Error handling
|
||||
|
||||
Lua allows low-level error handling with the `error` function and high-level error handling with the `assert` function. The `error` function raises an error and handles it with the `pcall` or `xpcall` function. The `assert` function checks a condition and raises an error if the condition is not met.
|
||||
|
||||
````lua
|
||||
|
||||
|
||||
|
||||
-- Throw an error if the first argument is false
|
||||
-- the second argument is the error message.
|
||||
assert(type(firstvariable) = 'string', 'not a string')
|
||||
|
||||
-- TODO to continue
|
||||
|
||||
````
|
||||
|
||||
### Modules
|
||||
|
||||
Modules are a way to organize your code. They are a way to group functions and variables together in a single file. You can then use the module in other files by using the `require` function.
|
||||
|
||||
````lua
|
||||
-- Suppose the file mod.lua looks like this:
|
||||
local M = {}
|
||||
|
||||
local function sayMyName()
|
||||
print('Hrunkner')
|
||||
end
|
||||
|
||||
function M.sayHello()
|
||||
print('Why hello there')
|
||||
sayMyName()
|
||||
end
|
||||
|
||||
return M -- Return the table M.
|
||||
|
||||
-- Another file can use mod.lua's functionality:
|
||||
local mod = require('mod') -- Run the file mod.lua.
|
||||
|
||||
-- require is the standard way to include modules.
|
||||
-- require acts like: (if not cached; see below)
|
||||
local mod = (function ()
|
||||
<contents of mod.lua>
|
||||
end)()
|
||||
-- It's like mod.lua is a function body, so that
|
||||
-- locals inside mod.lua are invisible outside it.
|
||||
|
||||
-- This works because mod here = M in mod.lua:
|
||||
mod.sayHello() -- Says hello to Hrunkner.
|
||||
|
||||
-- This is wrong, sayMyName only exists in mod.lua:
|
||||
mod.sayMyName() -- error
|
||||
|
||||
-- require's return values are cached so a file is
|
||||
-- run at most once, even when require'd many times.
|
||||
|
||||
-- Suppose mod2.lua contains "print('Hi!')".
|
||||
local a = require('mod2') -- Prints Hi!
|
||||
local b = require('mod2') -- Doesn't print; a=b.
|
||||
|
||||
-- dofile is like require without caching:
|
||||
dofile('mod2.lua') --> Hi!
|
||||
dofile('mod2.lua') --> Hi! (runs it again)
|
||||
|
||||
-- loadfile loads a lua file but doesn't run it yet.
|
||||
f = loadfile('mod2.lua') -- Call f() to run it.
|
||||
|
||||
-- loadstring is loadfile for strings.
|
||||
g = loadstring('print(343)') -- Returns a function.
|
||||
g() -- Prints out '343', nothing printed before now.
|
||||
|
||||
````
|
||||
|
||||
|
102
support/class.lua
Normal file
102
support/class.lua
Normal file
@ -0,0 +1,102 @@
|
||||
|
||||
-- ============================================================================
|
||||
-- This is a simple Person class (Raw example without synthetic sugar).
|
||||
-- ============================================================================
|
||||
Person1 = {}
|
||||
|
||||
-- Constructor
|
||||
function Person1.new(self, name, age)
|
||||
local o = {}
|
||||
self.__index = self
|
||||
setmetatable(o, self)
|
||||
o.name = name
|
||||
o.age = age
|
||||
return o
|
||||
end
|
||||
|
||||
-- Methods
|
||||
function Person1.getName(self)
|
||||
return self.name
|
||||
end
|
||||
|
||||
function Person1.getAge(self)
|
||||
return self.age
|
||||
end
|
||||
|
||||
-- Usage
|
||||
local instance = Person1.new(Person1, "John", 30)
|
||||
print('name: ' .. instance.getName(instance)) -- John
|
||||
print('age: ' .. instance.getAge(instance)) -- 30
|
||||
|
||||
-- Garbage collection
|
||||
Person1 = nil
|
||||
instance = nil
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- This is a simple Person class (Synthetic sugar example).
|
||||
-- ============================================================================
|
||||
Person2 = {}
|
||||
|
||||
-- Constructor
|
||||
function Person2:new(name, age)
|
||||
local o = {}
|
||||
self.__index = self
|
||||
setmetatable(o, self)
|
||||
o.name = name
|
||||
o.age = age
|
||||
return o
|
||||
end
|
||||
|
||||
-- Methods
|
||||
function Person2:getName()
|
||||
return self.name
|
||||
end
|
||||
|
||||
function Person2:getAge()
|
||||
return self.age
|
||||
end
|
||||
|
||||
-- Usage
|
||||
local instance = Person2:new("John Doe", 50)
|
||||
print('name: ' .. instance:getName()) -- John Doe
|
||||
print('age: ' .. instance:getAge()) -- 50
|
||||
|
||||
-- Garbage collection
|
||||
Person2 = nil
|
||||
instance = nil
|
||||
|
||||
|
||||
-- ============================================================================
|
||||
-- This is my class definition method (with Synthetic sugar example).
|
||||
-- ============================================================================
|
||||
Person = {}
|
||||
|
||||
-- Constructor
|
||||
function Person:new(name, age)
|
||||
local this = setmetatable({}, {__index = self})
|
||||
this.name = name or 'EndMove'
|
||||
this.age = age or 20
|
||||
return this
|
||||
end
|
||||
|
||||
-- Methods
|
||||
function Person:getFName()
|
||||
return 'name: ' .. self.name
|
||||
end
|
||||
|
||||
function Person:getFAge()
|
||||
return 'age: ' .. self.age
|
||||
end
|
||||
|
||||
-- Usage
|
||||
local instance = Person:new("Gashy", 21)
|
||||
print(instance:getFName()) -- name: Gashy
|
||||
print(instance:getFAge()) -- age: 21
|
||||
|
||||
-- Garbage collection
|
||||
Person = nil
|
||||
instance = nil
|
||||
|
||||
-- ============================================================================
|
||||
-- Thanks for reading!
|
@ -1,3 +1,8 @@
|
||||
|
||||
-- ============================================================================
|
||||
-- Let's study the different loops offered by the Lua language.
|
||||
-- ============================================================================
|
||||
|
||||
-- Jeb while loop
|
||||
local jebSum = 0
|
||||
print('jeb : '..jebSum)
|
||||
@ -39,3 +44,6 @@ while true do
|
||||
if true then break end
|
||||
end
|
||||
print('Breaking out -> Done')
|
||||
|
||||
-- ============================================================================
|
||||
-- Thanks for reading!
|
Loading…
Reference in New Issue
Block a user