mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2025-04-27 15:43:58 +00:00
Merge branch 'master' of github.com:geoffliu/learnxinyminutes-docs
This commit is contained in:
commit
31faf1a6a1
@ -22,6 +22,11 @@ Send a pull request or open an issue any time of day or night.
|
||||
**(e.g. [python/en] for English Python).** This will help everyone pick out things they
|
||||
care about.
|
||||
|
||||
We're happy for any contribution in any form, but if you're making more than one major change
|
||||
(i.e. translations for two different languages) it would be super cool of you to make a
|
||||
separate pull request for each one so that someone can review them more effectively and/or
|
||||
individually.
|
||||
|
||||
### Style Guidelines
|
||||
|
||||
* **Keep lines under 80 chars**
|
||||
|
@ -26,13 +26,15 @@ Multi-line comments look like this. They work in C89 as well.
|
||||
Multi-line comments don't nest /* Be careful */ // comment ends on this line...
|
||||
*/ // ...not this one!
|
||||
|
||||
// Constants: #define <keyword>
|
||||
// Constants: #define <keyword>
|
||||
#define DAYS_IN_YEAR 365
|
||||
|
||||
// Enumeration constants are also ways to declare constants.
|
||||
enum days {SUN = 1, MON, TUE, WED, THU, FRI, SAT};
|
||||
// Enumeration constants are also ways to declare constants.
|
||||
// All statements must end with a semicolon
|
||||
enum days {SUN = 1, MON, TUE, WED, THU, FRI, SAT};
|
||||
// MON gets 2 automatically, TUE gets 3, etc.
|
||||
|
||||
|
||||
// Import headers with #include
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@ -57,7 +59,6 @@ int main() {
|
||||
// print output using printf, for "print formatted"
|
||||
// %d is an integer, \n is a newline
|
||||
printf("%d\n", 0); // => Prints 0
|
||||
// All statements must end with a semicolon
|
||||
|
||||
///////////////////////////////////////
|
||||
// Types
|
||||
@ -385,7 +386,8 @@ int main() {
|
||||
// or when it's the argument of the `sizeof` or `alignof` operator:
|
||||
int arraythethird[10];
|
||||
int *ptr = arraythethird; // equivalent with int *ptr = &arr[0];
|
||||
printf("%zu, %zu\n", sizeof arraythethird, sizeof ptr); // probably prints "40, 4" or "40, 8"
|
||||
printf("%zu, %zu\n", sizeof arraythethird, sizeof ptr);
|
||||
// probably prints "40, 4" or "40, 8"
|
||||
|
||||
|
||||
// Pointers are incremented and decremented based on their type
|
||||
@ -476,7 +478,7 @@ void testFunc() {
|
||||
}
|
||||
|
||||
//make external variables private to source file with static:
|
||||
static int j = 0; //other files using testFunc() cannot access variable i
|
||||
static int j = 0; //other files using testFunc2() cannot access variable j
|
||||
void testFunc2() {
|
||||
extern int j;
|
||||
}
|
||||
|
@ -678,6 +678,23 @@ on a new line! ""Wow!"", the masses cried";
|
||||
private set;
|
||||
}
|
||||
|
||||
// It's also possible to define custom Indexers on objects.
|
||||
// All though this is not entirely useful in this example, you
|
||||
// could do bicycle[0] which yields "chris" to get the first passenger or
|
||||
// bicycle[1] = "lisa" to set the passenger. (of this apparent quattrocycle)
|
||||
private string[] passengers = { "chris", "phil", "darren", "regina" }
|
||||
|
||||
public string this[int i]
|
||||
{
|
||||
get {
|
||||
return passengers[i];
|
||||
}
|
||||
|
||||
set {
|
||||
return passengers[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
//Method to display the attribute values of this Object.
|
||||
public virtual string Info()
|
||||
{
|
||||
|
@ -12,7 +12,7 @@ such as Open Firmware. It's also used by NASA.
|
||||
Note: This article focuses predominantly on the Gforth implementation of
|
||||
Forth, but most of what is written here should work elsewhere.
|
||||
|
||||
```forth
|
||||
```
|
||||
\ This is a comment
|
||||
( This is also a comment but it's only used when defining words )
|
||||
|
||||
|
@ -13,7 +13,7 @@ Brainfuck (sans majuscule à part au début d’une phrase) est un langage
|
||||
Turing-complet extrêmement simple avec seulement 8 commandes.
|
||||
|
||||
```
|
||||
Tout caractère en dehors de "><+-.,[]" (en dehors des guillements) est ignoré.
|
||||
Tout caractère en dehors de "><+-.,[]" (en dehors des guillemets) est ignoré.
|
||||
|
||||
Brainfuck est représenté par un tableau de 30 000 cellules initialisées à 0 et
|
||||
un pointeur de données pointant sur la cellule courante.
|
||||
|
@ -484,7 +484,7 @@ class LearnHaxe3{
|
||||
// we can read this variable
|
||||
trace(foo_instance.public_read + " is the value for foo_instance.public_read");
|
||||
// but not write it
|
||||
// foo_instance.public_write = 4; // this will throw an error if uncommented:
|
||||
// foo_instance.public_read = 4; // this will throw an error if uncommented:
|
||||
// trace(foo_instance.public_write); // as will this.
|
||||
|
||||
trace(foo_instance + " is the value for foo_instance"); // calls the toString method
|
||||
|
@ -83,7 +83,7 @@ True ; => True
|
||||
(greet "bilbo") ;=> "hello bilbo"
|
||||
|
||||
; functions can take optional arguments as well as keyword arguments
|
||||
(defn foolist [arg1 &optional [arg2 2]]
|
||||
(defn foolists [arg1 &optional [arg2 2]]
|
||||
[arg1 arg2])
|
||||
|
||||
(foolists 3) ;=> [3 2]
|
||||
|
@ -4,6 +4,7 @@ language: java
|
||||
contributors:
|
||||
- ["Jake Prather", "http://github.com/JakeHP"]
|
||||
- ["Madison Dickson", "http://github.com/mix3d"]
|
||||
- ["Jakukyo Friel", "http://weakish.github.io"]
|
||||
filename: LearnJava.java
|
||||
|
||||
---
|
||||
@ -49,7 +50,7 @@ public class LearnJava {
|
||||
// Types & Variables
|
||||
///////////////////////////////////////
|
||||
|
||||
// Declare a variable using <type> <name> [
|
||||
// Declare a variable using <type> <name>
|
||||
// Byte - 8-bit signed two's complement integer
|
||||
// (-128 <= byte <= 127)
|
||||
byte fooByte = 100;
|
||||
@ -268,9 +269,9 @@ public class LearnJava {
|
||||
System.out.println(bar); // Prints A, because the statement is true
|
||||
|
||||
|
||||
///////////////////////////////////////
|
||||
// Converting Data Types And Typcasting
|
||||
///////////////////////////////////////
|
||||
////////////////////////////////////////
|
||||
// Converting Data Types And Typecasting
|
||||
////////////////////////////////////////
|
||||
|
||||
// Converting data
|
||||
|
||||
@ -433,10 +434,12 @@ public interface Digestible {
|
||||
|
||||
//We can now create a class that implements both of these interfaces
|
||||
public class Fruit implements Edible, Digestible {
|
||||
@Override
|
||||
public void eat() {
|
||||
//...
|
||||
}
|
||||
|
||||
@Override
|
||||
public void digest() {
|
||||
//...
|
||||
}
|
||||
@ -445,10 +448,12 @@ public class Fruit implements Edible, Digestible {
|
||||
//In java, you can extend only one class, but you can implement many interfaces.
|
||||
//For example:
|
||||
public class ExampleClass extends ExampleClassParent implements InterfaceOne, InterfaceTwo {
|
||||
@Override
|
||||
public void InterfaceOneMethod() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void InterfaceTwoMethod() {
|
||||
|
||||
}
|
||||
|
@ -219,8 +219,8 @@ identity 1 # => 1
|
||||
|
||||
# Operators are not functions in LiveScript, but you can easily turn
|
||||
# them into one! Enter the operator sectioning:
|
||||
divide-by-2 = (/ 2)
|
||||
[2, 4, 8, 16].map(divide-by-2) .reduce (+)
|
||||
divide-by-two = (/ 2)
|
||||
[2, 4, 8, 16].map(divide-by-two) .reduce (+)
|
||||
|
||||
|
||||
# Not only of function application lives LiveScript, as in any good
|
||||
@ -248,8 +248,8 @@ reduce = (f, xs, initial) --> xs.reduce f, initial
|
||||
# The underscore is also used in regular partial application, which you
|
||||
# can use for any function:
|
||||
div = (left, right) -> left / right
|
||||
div-by-2 = div _, 2
|
||||
div-by-2 4 # => 2
|
||||
div-by-two = div _, 2
|
||||
div-by-two 4 # => 2
|
||||
|
||||
|
||||
# Last, but not least, LiveScript has back-calls, which might help
|
||||
|
@ -35,7 +35,8 @@ my $variable;
|
||||
## * Scalars. They represent a single value. They start with a `$`
|
||||
|
||||
my $str = 'String';
|
||||
my $str2 = "String"; # double quotes allow for interpolation
|
||||
# double quotes allow for interpolation (which we'll see later):
|
||||
my $str2 = "String";
|
||||
|
||||
# variable names can contain but not end with simple quotes and dashes,
|
||||
# and can contain (and end with) underscores :
|
||||
@ -66,23 +67,13 @@ my @keys = 0, 2;
|
||||
@array[@keys] = @letters; # Assign using an array
|
||||
say @array; #=> a 6 b
|
||||
|
||||
# There are two more kinds of lists: Parcel and Arrays.
|
||||
# Parcels are immutable lists (you can't modify a list that's not assigned).
|
||||
# This is a parcel:
|
||||
(1, 2, 3); # Not assigned to anything. Changing an element would provoke an error
|
||||
# This is a list:
|
||||
my @a = (1, 2, 3); # Assigned to `@a`. Changing elements is okay!
|
||||
|
||||
# Lists flatten (in list context). You'll see below how to apply item context
|
||||
# or use arrays to have real nested lists.
|
||||
|
||||
|
||||
## * Hashes. Key-Value Pairs.
|
||||
# Hashes are actually arrays of Pairs (`Key => Value`),
|
||||
# except they get "flattened", removing duplicated keys.
|
||||
## * Hashes, or key-value Pairs.
|
||||
# Hashes are actually arrays of Pairs
|
||||
# (you can construct a Pair object using the syntax `Key => Value`),
|
||||
# except they get "flattened" (hash context), removing duplicated keys.
|
||||
my %hash = 1 => 2,
|
||||
3 => 4;
|
||||
my %hash = autoquoted => "key", # keys *can* get auto-quoted
|
||||
my %hash = autoquoted => "key", # keys get auto-quoted
|
||||
"some other" => "value", # trailing commas are okay
|
||||
;
|
||||
my %hash = <key1 value1 key2 value2>; # you can also create a hash
|
||||
@ -112,6 +103,63 @@ sub say-hello-to(Str $name) { # You can provide the type of an argument
|
||||
say "Hello, $name !";
|
||||
}
|
||||
|
||||
## It can also have optional arguments:
|
||||
sub with-optional($arg?) { # the "?" marks the argument optional
|
||||
say "I might return `(Any)` if I don't have an argument passed,
|
||||
or I'll return my argument";
|
||||
$arg;
|
||||
}
|
||||
with-optional; # returns Any
|
||||
with-optional(); # returns Any
|
||||
with-optional(1); # returns 1
|
||||
|
||||
## You can also give them a default value when they're not passed:
|
||||
sub hello-to($name = "World") {
|
||||
say "Hello, $name !";
|
||||
}
|
||||
hello-to; #=> Hello, World !
|
||||
hello-to(); #=> Hello, World !
|
||||
hello-to('You'); #=> Hello, You !
|
||||
|
||||
## You can also, by using a syntax akin to the one of hashes (yay unified syntax !),
|
||||
## pass *named* arguments to a `sub`.
|
||||
# They're optional, and will default to "Any" (Perl's "null"-like value).
|
||||
sub with-named($normal-arg, :$named) {
|
||||
say $normal-arg + $named;
|
||||
}
|
||||
with-named(1, named => 6); #=> 7
|
||||
# There's one gotcha to be aware of, here:
|
||||
# If you quote your key, Perl 6 won't be able to see it at compile time,
|
||||
# and you'll have a single Pair object as a positional paramater,
|
||||
# which means this fails:
|
||||
with-named(1, 'named' => 6);
|
||||
|
||||
with-named(2, :named(5)); #=> 7
|
||||
|
||||
# To make a named argument mandatory, you can use `?`'s inverse, `!`
|
||||
sub with-mandatory-named(:$str!) {
|
||||
say "$str !";
|
||||
}
|
||||
with-mandatory-named(str => "My String"); #=> My String !
|
||||
with-mandatory-named; # run time error: "Required named parameter not passed"
|
||||
with-mandatory-named(3); # run time error: "Too many positional parameters passed"
|
||||
|
||||
## If a sub takes a named boolean argument ...
|
||||
sub takes-a-bool($name, :$bool) {
|
||||
say "$name takes $bool";
|
||||
}
|
||||
# ... you can use the same "short boolean" hash syntax:
|
||||
takes-a-bool('config', :bool); # config takes True
|
||||
takes-a-bool('config', :!bool); # config takes False
|
||||
|
||||
## You can also provide your named arguments with defaults:
|
||||
sub named-def(:$def = 5) {
|
||||
say $def;
|
||||
}
|
||||
named-def; #=> 5
|
||||
named-def(:10def); #=> 10
|
||||
named-def(def => 15); #=> 15
|
||||
|
||||
# Since you can omit parenthesis to call a function with no arguments,
|
||||
# you need "&" in the name to capture `say-hello`.
|
||||
my &s = &say-hello;
|
||||
@ -136,74 +184,6 @@ sub concat3($a, $b, $c) {
|
||||
concat3(|@array); #=> a, b, c
|
||||
# `@array` got "flattened" as a part of the argument list
|
||||
|
||||
## It can also have optional arguments:
|
||||
sub with-optional($arg?) { # the "?" marks the argument optional
|
||||
say "I might return `(Any)` if I don't have an argument passed,
|
||||
or I'll return my argument";
|
||||
$arg;
|
||||
}
|
||||
with-optional; # returns Any
|
||||
with-optional(); # returns Any
|
||||
with-optional(1); # returns 1
|
||||
|
||||
## You can also give them a default value when they're not passed:
|
||||
sub hello-to($name = "World") {
|
||||
say "Hello, $name !";
|
||||
}
|
||||
hello-to; #=> Hello, World !
|
||||
hello-to(); #=> Hello, World !
|
||||
hello-to('You'); #=> Hello, You !
|
||||
|
||||
## You can also, by using a syntax akin to the one of hashes (yay unification !),
|
||||
## pass *named* arguments to a `sub`.
|
||||
sub with-named($normal-arg, :$named) {
|
||||
say $normal-arg + $named;
|
||||
}
|
||||
with-named(1, named => 6); #=> 7
|
||||
# There's one gotcha to be aware of, here:
|
||||
# If you quote your key, Perl 6 won't be able to see it at compile time,
|
||||
# and you'll have a single Pair object as a positional paramater.
|
||||
|
||||
with-named(2, :named(5)); #=> 7
|
||||
with-named(3, :4named); #=> 7
|
||||
# (special colon pair syntax for numbers,
|
||||
# to be used with s// and such, see later)
|
||||
|
||||
with-named(3); # warns, because we tried to use the undefined $named in a `+`:
|
||||
# by default, named arguments are *optional*
|
||||
|
||||
# To make a named argument mandatory, you can use `?`'s inverse, `!`
|
||||
sub with-mandatory-named(:$str!) {
|
||||
say "$str !";
|
||||
}
|
||||
with-mandatory-named(str => "My String"); #=> My String !
|
||||
with-mandatory-named; # run time error: "Required named parameter not passed"
|
||||
with-mandatory-named(3); # run time error: "Too many positional parameters passed"
|
||||
|
||||
## If a sub takes a named boolean argument ...
|
||||
sub takes-a-bool($name, :$bool) {
|
||||
say "$name takes $bool";
|
||||
}
|
||||
# ... you can use the same "short boolean" hash syntax:
|
||||
takes-a-bool('config', :bool); # config takes True
|
||||
takes-a-bool('config', :!bool); # config takes False
|
||||
# or you can use the "adverb" form:
|
||||
takes-a-bool('config'):bool; #=> config takes True
|
||||
takes-a-bool('config'):!bool; #=> config takes False
|
||||
# You'll learn to love (or maybe hate, eh) that syntax later.
|
||||
|
||||
|
||||
## You can also provide your named arguments with defaults:
|
||||
sub named-def(:$def = 5) {
|
||||
say $def;
|
||||
}
|
||||
named-def; #=> 5
|
||||
named-def(:10def); #=> 10
|
||||
named-def(def => 15); #=> 15
|
||||
|
||||
# -- Note: we're going to learn *more* on subs really soon,
|
||||
# but we need to grasp a few more things to understand their real power. Ready?
|
||||
|
||||
### Containers
|
||||
# In Perl 6, values are actually stored in "containers".
|
||||
# The assignment operator asks the container on the left to store the value on
|
||||
@ -220,23 +200,19 @@ sub mutate($n is rw) {
|
||||
|
||||
# A sub itself returns a container, which means it can be marked as rw:
|
||||
my $x = 42;
|
||||
sub mod() is rw { $x }
|
||||
mod() = 52; # in this case, the parentheses are mandatory
|
||||
# (else Perl 6 thinks `mod` is a "term")
|
||||
sub x-store() is rw { $x }
|
||||
x-store() = 52; # in this case, the parentheses are mandatory
|
||||
# (else Perl 6 thinks `mod` is an identifier)
|
||||
say $x; #=> 52
|
||||
|
||||
|
||||
### Control Flow Structures
|
||||
|
||||
# You don't need to put parenthesis around the condition,
|
||||
# but that also means you always have to use brackets (`{ }`) for their body:
|
||||
|
||||
## Conditionals
|
||||
|
||||
# - `if`
|
||||
# Before talking about `if`, we need to know which values are "Truthy"
|
||||
# (represent True), and which are "Falsey" (or "Falsy") -- represent False.
|
||||
# Only these values are Falsey: (), 0, "0", Nil, A type (like `Str` or `Int`),
|
||||
# Only these values are Falsey: (), 0, "0", "", Nil, A type (like `Str` or `Int`),
|
||||
# and of course False itself.
|
||||
# Every other value is Truthy.
|
||||
if True {
|
||||
@ -247,30 +223,38 @@ unless False {
|
||||
say "It's not false !";
|
||||
}
|
||||
|
||||
# As you can see, you don't need parentheses around conditions.
|
||||
# However, you do need the brackets around the "body" block:
|
||||
# if (true) say; # This doesn't work !
|
||||
|
||||
# You can also use their postfix versions, with the keyword after:
|
||||
say "Quite truthy" if True;
|
||||
|
||||
# if (true) say; # This doesn't work !
|
||||
|
||||
# - Ternary conditional, "?? !!" (like `x ? y : z` in some other languages)
|
||||
my $a = $condition ?? $value-if-true !! $value-if-false;
|
||||
|
||||
# - `given`-`when` looks like other languages `switch`, but much more
|
||||
# powerful thanks to smart matching and thanks to Perl 6's "topic variable", $_.
|
||||
#
|
||||
# This variable contains the default argument of a block,
|
||||
# a loop's current iteration (unless explicitly named), etc.
|
||||
#
|
||||
# `given` simply puts its argument into `$_` (like a block would do),
|
||||
# and `when` compares it using the "smart matching" (`~~`) operator.
|
||||
#
|
||||
# Since other Perl 6 constructs use this variable (as said before, like `for`,
|
||||
# blocks, etc), this means the powerful `when` is not only applicable along with
|
||||
# a `given`, but instead anywhere a `$_` exists.
|
||||
given "foo bar" {
|
||||
when /foo/ { # Don't worry about smart matching -- just know `when` uses it.
|
||||
say $_; #=> foo bar
|
||||
when /foo/ { # Don't worry about smart matching yet – just know `when` uses it.
|
||||
# This is equivalent to `if $_ ~~ /foo/`.
|
||||
say "Yay !";
|
||||
}
|
||||
when $_.chars > 50 { # smart matching anything with True (`$a ~~ True`) is True,
|
||||
# so you can also put "normal" conditionals.
|
||||
# This when is equivalent to this `if`:
|
||||
# if ($_.chars > 50) ~~ True {...}
|
||||
say "Quite a long string !";
|
||||
}
|
||||
default { # same as `when *` (using the Whatever Star)
|
||||
@ -281,7 +265,7 @@ given "foo bar" {
|
||||
## Looping constructs
|
||||
|
||||
# - `loop` is an infinite loop if you don't pass it arguments,
|
||||
# but can also be a c-style `for`:
|
||||
# but can also be a C-style `for` loop:
|
||||
loop {
|
||||
say "This is an infinite loop !";
|
||||
last; # last breaks out of the loop, like the `break` keyword in other languages
|
||||
@ -296,7 +280,7 @@ loop (my $i = 0; $i < 5; $i++) {
|
||||
|
||||
# - `for` - Passes through an array
|
||||
for @array -> $variable {
|
||||
say "I've found $variable !";
|
||||
say "I've got $variable !";
|
||||
}
|
||||
|
||||
# As we saw with given, for's default "current iteration" variable is `$_`.
|
||||
@ -316,22 +300,15 @@ for @array {
|
||||
last if $_ == 5; # Or break out of a loop (like `break` in C-like languages).
|
||||
}
|
||||
|
||||
# Note - the "lambda" `->` syntax isn't reserved to `for`:
|
||||
# The "pointy block" syntax isn't specific to for.
|
||||
# It's just a way to express a block in Perl6.
|
||||
if long-computation() -> $result {
|
||||
say "The result is $result";
|
||||
}
|
||||
|
||||
## Loops can also have a label, and be jumped to through these.
|
||||
OUTER: while 1 {
|
||||
say "hey";
|
||||
while 1 {
|
||||
OUTER.last; # All the control keywords must be called on the label itself
|
||||
}
|
||||
}
|
||||
|
||||
# Now that you've seen how to traverse a list, you need to be aware of something:
|
||||
# List context (@) flattens. If you traverse nested lists, you'll actually be traversing a
|
||||
# shallow list (except if some sub-list were put in item context ($)).
|
||||
# shallow list.
|
||||
for 1, 2, (3, (4, ((5)))) {
|
||||
say "Got $_.";
|
||||
} #=> Got 1. Got 2. Got 3. Got 4. Got 5.
|
||||
@ -348,9 +325,14 @@ for [1, 2, 3, 4] {
|
||||
say "Got $_.";
|
||||
} #=> Got 1 2 3 4.
|
||||
|
||||
# The other difference between `$()` and `[]` is that `[]` always returns a mutable Array
|
||||
# whereas `$()` will return a Parcel when given a Parcel.
|
||||
# You need to be aware of when flattening happens exactly.
|
||||
# The general guideline is that argument lists flatten, but not method calls.
|
||||
# Also note that `.list` and array assignment flatten (`@ary = ...`) flatten.
|
||||
((1,2), 3, (4,5)).map({...}); # iterates over three elements (method call)
|
||||
map {...}, ((1,2),3,(4,5)); # iterates over five elements (argument list is flattened)
|
||||
|
||||
(@a, @b, @c).pick(1); # picks one of three arrays (method call)
|
||||
pick 1, @a, @b, @c; # flattens argument list and pick one element
|
||||
|
||||
### Operators
|
||||
|
||||
@ -394,9 +376,6 @@ $arg ~~ &bool-returning-function; # `True` if the function, passed `$arg`
|
||||
1 ~~ True; # smart-matching against a boolean always returns that boolean
|
||||
# (and will warn).
|
||||
|
||||
# - `===` is value identity and uses `.WHICH` on the objects to compare them
|
||||
# - `=:=` is container identity and uses `VAR()` on the objects to compare them
|
||||
|
||||
# You also, of course, have `<`, `<=`, `>`, `>=`.
|
||||
# Their string equivalent are also avaiable : `lt`, `le`, `gt`, `ge`.
|
||||
3 > 4;
|
||||
@ -559,6 +538,21 @@ map(sub ($a, $b) { $a + $b + 3 }, @array); # (here with `sub`)
|
||||
# Note : those are sorted lexicographically.
|
||||
# `{ $^b / $^a }` is like `-> $a, $b { $b / $a }`
|
||||
|
||||
## About types...
|
||||
# Perl6 is gradually typed. This means you can specify the type
|
||||
# of your variables/arguments/return types, or you can omit them
|
||||
# and they'll default to "Any".
|
||||
# You obviously get access to a few base types, like Int and Str.
|
||||
# The constructs for declaring types are "class", "role",
|
||||
# which you'll see later.
|
||||
|
||||
# For now, let us examinate "subset":
|
||||
# a "subset" is a "sub-type" with additional checks.
|
||||
# For example: "a very big integer is an Int that's greater than 500"
|
||||
# You can specify the type you're subtyping (by default, Any),
|
||||
# and add additional checks with the "where" keyword:
|
||||
subset VeryBigInteger of Int where * > 500;
|
||||
|
||||
## Multiple Dispatch
|
||||
# Perl 6 can decide which variant of a `sub` to call based on the type of the
|
||||
# arguments, or on arbitrary preconditions, like with a type or a `where`:
|
||||
@ -567,20 +561,19 @@ map(sub ($a, $b) { $a + $b + 3 }, @array); # (here with `sub`)
|
||||
multi sub sayit(Int $n) { # note the `multi` keyword here
|
||||
say "Number: $n";
|
||||
}
|
||||
multi sayit(Str $s) } # the `sub` is the default
|
||||
multi sayit(Str $s) } # a multi is a `sub` by default
|
||||
say "String: $s";
|
||||
}
|
||||
sayit("foo"); # prints "String: foo"
|
||||
sayit(True); # fails at *compile time* with
|
||||
# "calling 'sayit' will never work with arguments of types ..."
|
||||
|
||||
# with arbitrary precondition:
|
||||
# with arbitrary precondition (remember subsets?):
|
||||
multi is-big(Int $n where * > 50) { "Yes !" } # using a closure
|
||||
multi is-big(Int $ where 10..50) { "Quite." } # Using smart-matching
|
||||
# (could use a regexp, etc)
|
||||
multi is-big(Int $) { "No" }
|
||||
|
||||
# You can also name these checks, by creating "subsets":
|
||||
subset Even of Int where * %% 2;
|
||||
|
||||
multi odd-or-even(Even) { "Even" } # The main case using the type.
|
||||
@ -724,7 +717,7 @@ role PrintableVal {
|
||||
}
|
||||
}
|
||||
|
||||
# you "use" a mixin with "does" :
|
||||
# you "import" a mixin (a "role") with "does":
|
||||
class Item does PrintableVal {
|
||||
has $.val;
|
||||
|
||||
@ -1083,9 +1076,7 @@ postcircumfix:<{ }>(%h, $key, :delete); # (you can call operators like that)
|
||||
# It's a prefix meta-operator that takes a binary functions and
|
||||
# one or many lists. If it doesn't get passed any argument,
|
||||
# it either return a "default value" for this operator
|
||||
# (a value that wouldn't change the result if passed as one
|
||||
# of the element of the list to be passed to the operator),
|
||||
# or `Any` if there's none (examples below).
|
||||
# (a meaningless value) or `Any` if there's none (examples below).
|
||||
#
|
||||
# Otherwise, it pops an element from the list(s) one at a time, and applies
|
||||
# the binary function to the last result (or the list's first element)
|
||||
@ -1107,9 +1098,7 @@ say [//] Nil, Any, False, 1, 5; #=> False
|
||||
# Default value examples:
|
||||
say [*] (); #=> 1
|
||||
say [+] (); #=> 0
|
||||
# In both cases, they're results that, were they in the lists,
|
||||
# wouldn't have any impact on the final value
|
||||
# (since N*1=N and N+0=N).
|
||||
# meaningless values, since N*1=N and N+0=N.
|
||||
say [//]; #=> (Any)
|
||||
# There's no "default value" for `//`.
|
||||
|
||||
@ -1163,90 +1152,6 @@ say @fib[^10]; #=> 1 1 2 3 5 8 13 21 34 55
|
||||
# That's why `@primes[^100]` will take a long time the first time you print
|
||||
# it, then be instant.
|
||||
|
||||
|
||||
## * Sort comparison
|
||||
# They return one value of the `Order` enum : `Less`, `Same` and `More`
|
||||
# (which numerify to -1, 0 or +1).
|
||||
1 <=> 4; # sort comparison for numerics
|
||||
'a' leg 'b'; # sort comparison for string
|
||||
$obj eqv $obj2; # sort comparison using eqv semantics
|
||||
|
||||
## * Generic ordering
|
||||
3 before 4; # True
|
||||
'b' after 'a'; # True
|
||||
|
||||
## * Short-circuit default operator
|
||||
# Like `or` and `||`, but instead returns the first *defined* value :
|
||||
say Any // Nil // 0 // 5; #=> 0
|
||||
|
||||
## * Short-circuit exclusive or (XOR)
|
||||
# Returns `True` if one (and only one) of its arguments is true
|
||||
say True ^^ False; #=> True
|
||||
|
||||
## * Flip Flop
|
||||
# The flip flop operators (`ff` and `fff`, equivalent to P5's `..`/`...`).
|
||||
# are operators that take two predicates to test:
|
||||
# They are `False` until their left side returns `True`, then are `True` until
|
||||
# their right side returns `True`.
|
||||
# Like for ranges, you can exclude the iteration when it became `True`/`False`
|
||||
# by using `^` on either side.
|
||||
# Let's start with an example :
|
||||
for <well met young hero we shall meet later> {
|
||||
# by default, `ff`/`fff` smart-match (`~~`) against `$_`:
|
||||
if 'met' ^ff 'meet' { # Won't enter the if for "met"
|
||||
# (explained in details below).
|
||||
.say
|
||||
}
|
||||
|
||||
if rand == 0 ff rand == 1 { # compare variables other than `$_`
|
||||
say "This ... probably will never run ...";
|
||||
}
|
||||
}
|
||||
# This will print "young hero we shall meet" (excluding "met"):
|
||||
# the flip-flop will start returning `True` when it first encounters "met"
|
||||
# (but will still return `False` for "met" itself, due to the leading `^`
|
||||
# on `ff`), until it sees "meet", which is when it'll start returning `False`.
|
||||
|
||||
# The difference between `ff` (awk-style) and `fff` (sed-style) is that
|
||||
# `ff` will test its right side right when its left side changes to `True`,
|
||||
# and can get back to `False` right away
|
||||
# (*except* it'll be `True` for the iteration that matched) -
|
||||
# While `fff` will wait for the next iteration to
|
||||
# try its right side, once its left side changed:
|
||||
.say if 'B' ff 'B' for <A B C B A>; #=> B B
|
||||
# because the right-hand-side was tested
|
||||
# directly (and returned `True`).
|
||||
# "B"s are printed since it matched that time
|
||||
# (it just went back to `False` right away).
|
||||
.say if 'B' fff 'B' for <A B C B A>; #=> B C B
|
||||
# The right-hand-side wasn't tested until
|
||||
# `$_` became "C"
|
||||
# (and thus did not match instantly).
|
||||
|
||||
# A flip-flop can change state as many times as needed:
|
||||
for <test start print it stop not printing start print again stop not anymore> {
|
||||
.say if $_ eq 'start' ^ff^ $_ eq 'stop'; # exclude both "start" and "stop",
|
||||
#=> "print this printing again"
|
||||
}
|
||||
|
||||
# you might also use a Whatever Star,
|
||||
# which is equivalent to `True` for the left side or `False` for the right:
|
||||
for (1, 3, 60, 3, 40, 60) { # Note: the parenthesis are superfluous here
|
||||
# (sometimes called "superstitious parentheses")
|
||||
.say if $_ > 50 ff *; # Once the flip-flop reaches a number greater than 50,
|
||||
# it'll never go back to `False`
|
||||
#=> 60 3 40 60
|
||||
}
|
||||
|
||||
# You can also use this property to create an `If`
|
||||
# that'll not go through the first time :
|
||||
for <a b c> {
|
||||
.say if * ^ff *; # the flip-flop is `True` and never goes back to `False`,
|
||||
# but the `^` makes it *not run* on the first iteration
|
||||
#=> b c
|
||||
}
|
||||
|
||||
|
||||
### Regular Expressions
|
||||
# I'm sure a lot of you have been waiting for this one.
|
||||
# Well, now that you know a good deal of Perl 6 already, we can get started.
|
||||
@ -1470,6 +1375,105 @@ multi MAIN('import', File, Str :$as) { ... } # omitting parameter name
|
||||
# As you can see, this is *very* powerful.
|
||||
# It even went as far as to show inline the constants.
|
||||
# (the type is only displayed if the argument is `$`/is named)
|
||||
|
||||
###
|
||||
### APPENDIX A:
|
||||
###
|
||||
### List of things
|
||||
###
|
||||
|
||||
# It's considered by now you know the Perl6 basics.
|
||||
# This section is just here to list some common operations,
|
||||
# but which are not in the "main part" of the tutorial to bloat it up
|
||||
|
||||
## Operators
|
||||
|
||||
|
||||
## * Sort comparison
|
||||
# They return one value of the `Order` enum : `Less`, `Same` and `More`
|
||||
# (which numerify to -1, 0 or +1).
|
||||
1 <=> 4; # sort comparison for numerics
|
||||
'a' leg 'b'; # sort comparison for string
|
||||
$obj eqv $obj2; # sort comparison using eqv semantics
|
||||
|
||||
## * Generic ordering
|
||||
3 before 4; # True
|
||||
'b' after 'a'; # True
|
||||
|
||||
## * Short-circuit default operator
|
||||
# Like `or` and `||`, but instead returns the first *defined* value :
|
||||
say Any // Nil // 0 // 5; #=> 0
|
||||
|
||||
## * Short-circuit exclusive or (XOR)
|
||||
# Returns `True` if one (and only one) of its arguments is true
|
||||
say True ^^ False; #=> True
|
||||
## * Flip Flop
|
||||
# The flip flop operators (`ff` and `fff`, equivalent to P5's `..`/`...`).
|
||||
# are operators that take two predicates to test:
|
||||
# They are `False` until their left side returns `True`, then are `True` until
|
||||
# their right side returns `True`.
|
||||
# Like for ranges, you can exclude the iteration when it became `True`/`False`
|
||||
# by using `^` on either side.
|
||||
# Let's start with an example :
|
||||
for <well met young hero we shall meet later> {
|
||||
# by default, `ff`/`fff` smart-match (`~~`) against `$_`:
|
||||
if 'met' ^ff 'meet' { # Won't enter the if for "met"
|
||||
# (explained in details below).
|
||||
.say
|
||||
}
|
||||
|
||||
if rand == 0 ff rand == 1 { # compare variables other than `$_`
|
||||
say "This ... probably will never run ...";
|
||||
}
|
||||
}
|
||||
# This will print "young hero we shall meet" (excluding "met"):
|
||||
# the flip-flop will start returning `True` when it first encounters "met"
|
||||
# (but will still return `False` for "met" itself, due to the leading `^`
|
||||
# on `ff`), until it sees "meet", which is when it'll start returning `False`.
|
||||
|
||||
# The difference between `ff` (awk-style) and `fff` (sed-style) is that
|
||||
# `ff` will test its right side right when its left side changes to `True`,
|
||||
# and can get back to `False` right away
|
||||
# (*except* it'll be `True` for the iteration that matched) -
|
||||
# While `fff` will wait for the next iteration to
|
||||
# try its right side, once its left side changed:
|
||||
.say if 'B' ff 'B' for <A B C B A>; #=> B B
|
||||
# because the right-hand-side was tested
|
||||
# directly (and returned `True`).
|
||||
# "B"s are printed since it matched that time
|
||||
# (it just went back to `False` right away).
|
||||
.say if 'B' fff 'B' for <A B C B A>; #=> B C B
|
||||
# The right-hand-side wasn't tested until
|
||||
# `$_` became "C"
|
||||
# (and thus did not match instantly).
|
||||
|
||||
# A flip-flop can change state as many times as needed:
|
||||
for <test start print it stop not printing start print again stop not anymore> {
|
||||
.say if $_ eq 'start' ^ff^ $_ eq 'stop'; # exclude both "start" and "stop",
|
||||
#=> "print this printing again"
|
||||
}
|
||||
|
||||
# you might also use a Whatever Star,
|
||||
# which is equivalent to `True` for the left side or `False` for the right:
|
||||
for (1, 3, 60, 3, 40, 60) { # Note: the parenthesis are superfluous here
|
||||
# (sometimes called "superstitious parentheses")
|
||||
.say if $_ > 50 ff *; # Once the flip-flop reaches a number greater than 50,
|
||||
# it'll never go back to `False`
|
||||
#=> 60 3 40 60
|
||||
}
|
||||
|
||||
# You can also use this property to create an `If`
|
||||
# that'll not go through the first time :
|
||||
for <a b c> {
|
||||
.say if * ^ff *; # the flip-flop is `True` and never goes back to `False`,
|
||||
# but the `^` makes it *not run* on the first iteration
|
||||
#=> b c
|
||||
}
|
||||
|
||||
|
||||
# - `===` is value identity and uses `.WHICH` on the objects to compare them
|
||||
# - `=:=` is container identity and uses `VAR()` on the objects to compare them
|
||||
|
||||
```
|
||||
|
||||
If you want to go further, you can:
|
||||
@ -1477,5 +1481,5 @@ If you want to go further, you can:
|
||||
- Read the [Perl 6 Advent Calendar](http://perl6advent.wordpress.com/). This is probably the greatest source of Perl 6 information, snippets and such.
|
||||
- Come along on `#perl6` at `irc.freenode.net`. The folks here are always helpful.
|
||||
- Check the [source of Perl 6's functions and classes](https://github.com/rakudo/rakudo/tree/nom/src/core). Rakudo is mainly written in Perl 6 (with a lot of NQP, "Not Quite Perl", a Perl 6 subset easier to implement and optimize).
|
||||
- Read the [Synopses](perlcabal.org/syn). They explain it from an implementor point-of-view, but it's still very interesting.
|
||||
- Read [the language design documents](http://design.perl6.org). They explain P6 from an implementor point-of-view, but it's still very interesting.
|
||||
|
||||
|
@ -199,4 +199,4 @@ That's it.
|
||||
|
||||
Download [Node.js](http://nodejs.org/) and `npm install pogo`.
|
||||
|
||||
There is plenty of documentation on [http://pogoscript.org/](http://pogoscript.org/), inlcuding a [cheat sheet](http://pogoscript.org/cheatsheet.html), a [guide](http://pogoscript.org/guide/), and how [Pogoscript translates to Javascript](http://featurist.github.io/pogo-examples/). Get in touch on the [google group](http://groups.google.com/group/pogoscript) if you have questions!
|
||||
There is plenty of documentation on [http://pogoscript.org/](http://pogoscript.org/), including a [cheat sheet](http://pogoscript.org/cheatsheet.html), a [guide](http://pogoscript.org/guide/), and how [Pogoscript translates to Javascript](http://featurist.github.io/pogo-examples/). Get in touch on the [google group](http://groups.google.com/group/pogoscript) if you have questions!
|
||||
|
384
pt-br/clojure-pt.html.markdown
Normal file
384
pt-br/clojure-pt.html.markdown
Normal file
@ -0,0 +1,384 @@
|
||||
---
|
||||
language: clojure
|
||||
filename: learnclojure-pt.clj
|
||||
contributors:
|
||||
- ["Adam Bard", "http://adambard.com/"]
|
||||
translators:
|
||||
- ["Mariane Siqueira Machado", "https://twitter.com/mariane_sm"]
|
||||
lang: pt-br
|
||||
---
|
||||
|
||||
Clojure é uma linguagem da família do Lisp desenvolvida para a JVM (máquina virtual Java). Possui uma ênfase muito mais forte em [programação funcional] (https://pt.wikipedia.org/wiki/Programa%C3%A7%C3%A3o_funcional) pura do que Common Lisp, mas inclui diversas utilidades [STM](https://en.wikipedia.org/wiki/Software_transactional_memory) para lidar com estado a medida que isso se torna necessário.
|
||||
|
||||
Essa combinação permite gerenciar processamento concorrente de maneira muito simples, e frequentemente de maneira automática.
|
||||
|
||||
(Sua versão de clojure precisa ser pelo menos 1.2)
|
||||
|
||||
|
||||
```clojure
|
||||
; Comentários começam por ponto e vírgula
|
||||
|
||||
; Clojure é escrito em "forms", os quais são simplesmente
|
||||
; listas de coisas dentro de parênteses, separados por espaços em branco.
|
||||
|
||||
; O "reader" (leitor) de Clojure presume que o primeiro elemento de
|
||||
; uma par de parênteses é uma função ou macro, e que os resto são argumentos.
|
||||
|
||||
: A primeira chamada de um arquivo deve ser ns, para configurar o namespace (espaço de nomes)
|
||||
(ns learnclojure)
|
||||
|
||||
; Alguns exemplos básicos:
|
||||
|
||||
; str cria uma string concatenando seus argumentos
|
||||
(str "Hello" " " "World") ; => "Hello World"
|
||||
|
||||
; Cálculos são feitos de forma direta e intuitiva
|
||||
(+ 1 1) ; => 2
|
||||
(- 2 1) ; => 1
|
||||
(* 1 2) ; => 2
|
||||
(/ 2 1) ; => 2
|
||||
|
||||
; Você pode comparar igualdade utilizando =
|
||||
(= 1 1) ; => true
|
||||
(= 2 1) ; => false
|
||||
|
||||
; Negação para operações lógicas
|
||||
(not true) ; => false
|
||||
|
||||
; Aninhar "forms" funciona como esperado
|
||||
(+ 1 (- 3 2)) ; = 1 + (3 - 2) => 2
|
||||
|
||||
; Tipos
|
||||
;;;;;;;;;;;;;
|
||||
|
||||
; Clojure usa os tipos de objetos de Java para booleanos, strings e números.
|
||||
; Use `class` para inspecioná-los
|
||||
(class 1) ; Literais Integer são java.lang.Long por padrão
|
||||
(class 1.); Literais Float são java.lang.Double
|
||||
(class ""); Strings são sempre com aspas duplas, e são java.lang.String
|
||||
(class false) ; Booleanos são java.lang.Boolean
|
||||
(class nil); O valor "null" é chamado nil
|
||||
|
||||
; Se você quiser criar um lista de literais, use aspa simples para
|
||||
; ela não ser avaliada
|
||||
'(+ 1 2) ; => (+ 1 2)
|
||||
; (que é uma abreviação de (quote (+ 1 2)))
|
||||
|
||||
; É possível avaliar uma lista com aspa simples
|
||||
(eval '(+ 1 2)) ; => 3
|
||||
|
||||
; Coleções e sequências
|
||||
;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
; Listas são estruturas encadeadas, enquanto vetores são implementados como arrays.
|
||||
; Listas e Vetores são classes Java também!
|
||||
(class [1 2 3]); => clojure.lang.PersistentVector
|
||||
(class '(1 2 3)); => clojure.lang.PersistentList
|
||||
|
||||
; Uma lista é escrita como (1 2 3), mas temos que colocar a aspa
|
||||
; simples para impedir o leitor (reader) de pensar que é uma função.
|
||||
; Também, (list 1 2 3) é o mesmo que '(1 2 3)
|
||||
|
||||
; "Coleções" são apenas grupos de dados
|
||||
; Listas e vetores são ambos coleções:
|
||||
(coll? '(1 2 3)) ; => true
|
||||
(coll? [1 2 3]) ; => true
|
||||
|
||||
; "Sequências" (seqs) são descrições abstratas de listas de dados.
|
||||
; Apenas listas são seqs.
|
||||
(seq? '(1 2 3)) ; => true
|
||||
(seq? [1 2 3]) ; => false
|
||||
|
||||
; Um seq precisa apenas prover uma entrada quando é acessada.
|
||||
; Portanto, já que seqs podem ser avaliadas sob demanda (lazy) -- elas podem definir séries infinitas:
|
||||
(range 4) ; => (0 1 2 3)
|
||||
(range) ; => (0 1 2 3 4 ...) (uma série infinita)
|
||||
(take 4 (range)) ; (0 1 2 3)
|
||||
|
||||
; Use cons para adicionar um item no início de uma lista ou vetor
|
||||
(cons 4 [1 2 3]) ; => (4 1 2 3)
|
||||
(cons 4 '(1 2 3)) ; => (4 1 2 3)
|
||||
|
||||
; Conj adiciona um item em uma coleção sempre do jeito mais eficiente.
|
||||
; Para listas, elas inserem no início. Para vetores, é inserido no final.
|
||||
(conj [1 2 3] 4) ; => [1 2 3 4]
|
||||
(conj '(1 2 3) 4) ; => (4 1 2 3)
|
||||
|
||||
; Use concat para concatenar listas e vetores
|
||||
(concat [1 2] '(3 4)) ; => (1 2 3 4)
|
||||
|
||||
; Use filter, map para interagir com coleções
|
||||
(map inc [1 2 3]) ; => (2 3 4)
|
||||
(filter even? [1 2 3]) ; => (2)
|
||||
|
||||
; Use reduce para reduzi-los
|
||||
(reduce + [1 2 3 4])
|
||||
; = (+ (+ (+ 1 2) 3) 4)
|
||||
; => 10
|
||||
|
||||
; Reduce pode receber um argumento para o valor inicial
|
||||
(reduce conj [] '(3 2 1))
|
||||
; = (conj (conj (conj [] 3) 2) 1)
|
||||
; => [3 2 1]
|
||||
|
||||
; Funções
|
||||
;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
; Use fn para criar novas funções. Uma função sempre retorna
|
||||
; sua última expressão.
|
||||
(fn [] "Hello World") ; => fn
|
||||
|
||||
; (É necessário colocar parênteses para chamá-los)
|
||||
((fn [] "Hello World")) ; => "Hello World"
|
||||
|
||||
; Você pode atribuir valores a variáveis utilizando def
|
||||
(def x 1)
|
||||
x ; => 1
|
||||
|
||||
; Atribua uma função para uma var
|
||||
(def hello-world (fn [] "Hello World"))
|
||||
(hello-world) ; => "Hello World"
|
||||
|
||||
; Você pode abreviar esse processo usando defn
|
||||
(defn hello-world [] "Hello World")
|
||||
|
||||
; O [] é uma lista de argumentos para um função.
|
||||
(defn hello [name]
|
||||
(str "Hello " name))
|
||||
(hello "Steve") ; => "Hello Steve"
|
||||
|
||||
; Você pode ainda usar essa abreviação para criar funcões:
|
||||
(def hello2 #(str "Hello " %1))
|
||||
(hello2 "Fanny") ; => "Hello Fanny"
|
||||
|
||||
; Vocé pode ter funções multi-variadic, isto é, com um número variável de argumentos
|
||||
(defn hello3
|
||||
([] "Hello World")
|
||||
([name] (str "Hello " name)))
|
||||
(hello3 "Jake") ; => "Hello Jake"
|
||||
(hello3) ; => "Hello World"
|
||||
|
||||
; Funções podem agrupar argumentos extras em uma seq
|
||||
(defn count-args [& args]
|
||||
(str "You passed " (count args) " args: " args))
|
||||
(count-args 1 2 3) ; => "You passed 3 args: (1 2 3)"
|
||||
|
||||
; Você pode misturar argumentos regulares e argumentos em seq
|
||||
(defn hello-count [name & args]
|
||||
(str "Hello " name ", you passed " (count args) " extra args"))
|
||||
(hello-count "Finn" 1 2 3)
|
||||
; => "Hello Finn, you passed 3 extra args"
|
||||
|
||||
|
||||
; Mapas
|
||||
;;;;;;;;;;
|
||||
|
||||
; Hash maps e array maps compartilham uma mesma interface. Hash maps são mais
|
||||
; rápidos para pesquisa mas não mantém a ordem da chave.
|
||||
(class {:a 1 :b 2 :c 3}) ; => clojure.lang.PersistentArrayMap
|
||||
(class (hash-map :a 1 :b 2 :c 3)) ; => clojure.lang.PersistentHashMap
|
||||
|
||||
; Arraymaps pode automaticamente se tornar hashmaps através da maioria das
|
||||
; operações se eles ficarem grandes o suficiente, portanto não há necessida de
|
||||
; se preocupar com isso.
|
||||
|
||||
;Mapas podem usar qualquer valor que se pode derivar um hash como chave
|
||||
|
||||
|
||||
; Mapas podem usar qualquer valor em que se pode derivar um hash como chave,
|
||||
; mas normalmente palavras-chave (keywords) são melhores.
|
||||
; Keywords são como strings mas com algumas vantagens.
|
||||
(class :a) ; => clojure.lang.Keyword
|
||||
|
||||
(def stringmap {"a" 1, "b" 2, "c" 3})
|
||||
stringmap ; => {"a" 1, "b" 2, "c" 3}
|
||||
|
||||
(def keymap {:a 1, :b 2, :c 3})
|
||||
keymap ; => {:a 1, :c 3, :b 2}
|
||||
|
||||
; A propósito, vírgulas são sempre tratadas como espaçoes em branco e não fazem nada.
|
||||
|
||||
; Recupere o valor de um mapa chamando ele como uma função
|
||||
(stringmap "a") ; => 1
|
||||
(keymap :a) ; => 1
|
||||
|
||||
; Uma palavra-chave pode ser usada pra recuperar os valores de um mapa
|
||||
(:b keymap) ; => 2
|
||||
|
||||
; Não tente isso com strings
|
||||
;("a" stringmap)
|
||||
; => Exception: java.lang.String cannot be cast to clojure.lang.IFn
|
||||
|
||||
; Buscar uma chave não presente retorna nil
|
||||
(stringmap "d") ; => nil
|
||||
|
||||
; Use assoc para adicionar novas chaves para hash-maps
|
||||
(def newkeymap (assoc keymap :d 4))
|
||||
newkeymap ; => {:a 1, :b 2, :c 3, :d 4}
|
||||
|
||||
; Mas lembre-se, tipos em Clojure são sempre imutáveis!
|
||||
keymap ; => {:a 1, :b 2, :c 3}
|
||||
|
||||
; Use dissoc para remover chaves
|
||||
(dissoc keymap :a :b) ; => {:c 3}
|
||||
|
||||
; Conjuntos
|
||||
;;;;;;
|
||||
|
||||
(class #{1 2 3}) ; => clojure.lang.PersistentHashSet
|
||||
(set [1 2 3 1 2 3 3 2 1 3 2 1]) ; => #{1 2 3}
|
||||
|
||||
; Adicione um membro com conj
|
||||
(conj #{1 2 3} 4) ; => #{1 2 3 4}
|
||||
|
||||
; Remova um membro com disj
|
||||
(disj #{1 2 3} 1) ; => #{2 3}
|
||||
|
||||
; Test por existência usando set como função:
|
||||
(#{1 2 3} 1) ; => 1
|
||||
(#{1 2 3} 4) ; => nil
|
||||
|
||||
; Existem muitas outras funções no namespace clojure.sets
|
||||
|
||||
; Forms úteis
|
||||
;;;;;;;;;;;;;;;;;
|
||||
|
||||
; Construções lógicas em Clojure são como macros, e
|
||||
; se parecem com as demais
|
||||
(if false "a" "b") ; => "b"
|
||||
(if false "a") ; => nil
|
||||
|
||||
; Use let para criar um novo escopo associando sîmbolos a valores (bindings)
|
||||
(let [a 1 b 2]
|
||||
(> a b)) ; => false
|
||||
|
||||
; Agrupe comandos juntos com "do"
|
||||
(do
|
||||
(print "Hello")
|
||||
"World") ; => "World" (prints "Hello")
|
||||
|
||||
; Funções tem um do implícito
|
||||
(defn print-and-say-hello [name]
|
||||
(print "Saying hello to " name)
|
||||
(str "Hello " name))
|
||||
(print-and-say-hello "Jeff") ;=> "Hello Jeff" (prints "Saying hello to Jeff")
|
||||
|
||||
; Assim como let
|
||||
(let [name "Urkel"]
|
||||
(print "Saying hello to " name)
|
||||
(str "Hello " name)) ; => "Hello Urkel" (prints "Saying hello to Urkel")
|
||||
|
||||
; Módulos
|
||||
;;;;;;;;;;;;;;;
|
||||
|
||||
; Use "use" para poder usar todas as funções de um modulo
|
||||
(use 'clojure.set)
|
||||
|
||||
; Agora nós podemos usar operações com conjuntos
|
||||
(intersection #{1 2 3} #{2 3 4}) ; => #{2 3}
|
||||
(difference #{1 2 3} #{2 3 4}) ; => #{1}
|
||||
|
||||
; Você pode escolher um subconjunto de funções para importar
|
||||
(use '[clojure.set :only [intersection]])
|
||||
|
||||
; Use require para importar um módulo
|
||||
(require 'clojure.string)
|
||||
|
||||
; Use / para chamar funções de um módulo
|
||||
; Aqui, o módulo é clojure.string e a função é blank?
|
||||
(clojure.string/blank? "") ; => true
|
||||
|
||||
; Você pode dar para um módulo um nome mais curto no import
|
||||
(require '[clojure.string :as str])
|
||||
(str/replace "This is a test." #"[a-o]" str/upper-case) ; => "THIs Is A tEst."
|
||||
; (#"" denota uma expressão regular literal)
|
||||
|
||||
; Você pode usar require (e até "use", mas escolha require) de um namespace utilizando :require.
|
||||
; Não é necessário usar aspa simples nos seus módulos se você usar desse jeito.
|
||||
(ns test
|
||||
(:require
|
||||
[clojure.string :as str]
|
||||
[clojure.set :as set]))
|
||||
|
||||
; Java
|
||||
;;;;;;;;;;;;;;;;;
|
||||
|
||||
; Java tem uma biblioteca padrão enorme e muito útil,
|
||||
; portanto é importante aprender como utiliza-la.
|
||||
|
||||
; Use import para carregar um modulo java
|
||||
(import java.util.Date)
|
||||
|
||||
; Você pode importar usando ns também.
|
||||
(ns test
|
||||
(:import java.util.Date
|
||||
java.util.Calendar))
|
||||
|
||||
; Use o nome da clase com um "." no final para criar uma nova instância
|
||||
(Date.) ; <a date object>
|
||||
|
||||
; Use . para chamar métodos. Ou, use o atalho ".method"
|
||||
(. (Date.) getTime) ; <a timestamp>
|
||||
(.getTime (Date.)) ; exatamente a mesma coisa.
|
||||
|
||||
; Use / para chamar métodos estáticos
|
||||
(System/currentTimeMillis) ; <a timestamp> (o módulo System está sempre presente)
|
||||
|
||||
; Use doto para pode lidar com classe (mutáveis) de forma mais tolerável
|
||||
(import java.util.Calendar)
|
||||
(doto (Calendar/getInstance)
|
||||
(.set 2000 1 1 0 0 0)
|
||||
.getTime) ; => A Date. set to 2000-01-01 00:00:00
|
||||
|
||||
; STM
|
||||
;;;;;;;;;;;;;;;;;
|
||||
|
||||
; Software Transactional Memory é o mecanismo que Clojure usa para gerenciar
|
||||
; estado persistente. Tem algumas construções em Clojure que o utilizam.
|
||||
|
||||
; O atom é o mais simples. Passe pra ele um valor inicial
|
||||
(def my-atom (atom {}))
|
||||
|
||||
; Atualize o atom com um swap!.
|
||||
; swap! pega uma funçnao and chama ela com o valor atual do atom
|
||||
; como primeiro argumento, e qualquer argumento restante como o segundo
|
||||
(swap! my-atom assoc :a 1) ; Coloca o valor do átomo my-atom como o resultado de (assoc {} :a 1)
|
||||
(swap! my-atom assoc :b 2) ; Coloca o valor do átomo my-atom como o resultado de (assoc {:a 1} :b 2)
|
||||
|
||||
; Use '@' para desreferenciar um atom e acessar seu valor
|
||||
my-atom ;=> Atom<#...> (Retorna o objeto do Atom)
|
||||
@my-atom ; => {:a 1 :b 2}
|
||||
|
||||
; Abaixo um contador simples usando um atom
|
||||
(def counter (atom 0))
|
||||
(defn inc-counter []
|
||||
(swap! counter inc))
|
||||
|
||||
(inc-counter)
|
||||
(inc-counter)
|
||||
(inc-counter)
|
||||
(inc-counter)
|
||||
(inc-counter)
|
||||
|
||||
@counter ; => 5
|
||||
|
||||
; Outras construção STM são refs e agents.
|
||||
; Refs: http://clojure.org/refs
|
||||
; Agents: http://clojure.org/agents
|
||||
```
|
||||
|
||||
### Leitura adicional
|
||||
|
||||
Esse tutorial está longe de ser exaustivo, mas deve ser suficiente para que você possa começar.
|
||||
|
||||
Clojure.org tem vários artigos:
|
||||
[http://clojure.org/](http://clojure.org/)
|
||||
|
||||
Clojuredocs.org tem documentação com exemplos para quase todas as funções principais (pertecentes ao core):
|
||||
[http://clojuredocs.org/quickref/Clojure%20Core](http://clojuredocs.org/quickref/Clojure%20Core)
|
||||
|
||||
4Clojure é um grande jeito de aperfeiçoar suas habilidades em Clojure/Programação Funcional:
|
||||
[http://www.4clojure.com/](http://www.4clojure.com/)
|
||||
|
||||
Clojure-doc.org tem um bom número de artigos para iniciantes:
|
||||
[http://clojure-doc.org/](http://clojure-doc.org/)
|
500
pt-br/swift-pt.html.markdown
Normal file
500
pt-br/swift-pt.html.markdown
Normal file
@ -0,0 +1,500 @@
|
||||
---
|
||||
language: swift
|
||||
contributors:
|
||||
- ["Grant Timmerman", "http://github.com/grant"],
|
||||
- ["Christopher Bess", "http://github.com/cbess"]
|
||||
translators:
|
||||
- ["Mariane Siqueira Machado", "https://twitter.com/mariane_sm"]
|
||||
lang: pt-br
|
||||
filename: learnswift.swift
|
||||
---
|
||||
|
||||
Swift é uma linguagem de programação para desenvolvimento de aplicações no iOS e OS X criada pela Apple. Criada para
|
||||
coexistir com Objective-C e para ser mais resiliente a código com erros, Swift foi apresentada em 2014 na Apple's
|
||||
developer conference WWDC. Foi construída com o compilador LLVM já incluído no Xcode 6 beta.
|
||||
|
||||
O livro oficial [Swift Programming Language] (https://itunes.apple.com/us/book/swift-programming-language/id881256329) da
|
||||
Apple já está disponível via IBooks (apenas em inglês).
|
||||
|
||||
Confira também o tutorial completo de Swift da Apple [getting started guide](https://developer.apple.com/library/prerelease/ios/referencelibrary/GettingStarted/LandingPage/index.html), também disponível apenas em inglês.
|
||||
|
||||
```swift
|
||||
// importa um módulo
|
||||
import UIKit
|
||||
|
||||
//
|
||||
// MARK: Noções básicas
|
||||
//
|
||||
|
||||
// Xcode supporta anotações para seu código e lista elas na barra de atalhos
|
||||
// MARK: Marca uma sessão
|
||||
// TODO: Faça algo logo
|
||||
// FIXME: Conserte esse código
|
||||
|
||||
println("Hello, world")
|
||||
|
||||
// Valores em variáveis (var) podem ter seu valor alterado depois de declarados.
|
||||
// Valores em constantes (let) NÃO podem ser alterados depois de declarados.
|
||||
|
||||
var myVariable = 42
|
||||
let øπΩ = "value" // nomes de variáveis em unicode
|
||||
let π = 3.1415926
|
||||
let convenience = "keyword" // nome de variável contextual
|
||||
let weak = "keyword"; let override = "another keyword" // comandos podem ser separados por uma ponto e vírgula
|
||||
let `class` = "keyword" // Crases permitem que palavras-chave seja usadas como nome de variáveis
|
||||
let explicitDouble: Double = 70
|
||||
let intValue = 0007 // 7
|
||||
let largeIntValue = 77_000 // 77000
|
||||
let label = "some text " + String(myVariable) // Coerção
|
||||
let piText = "Pi = \(π), Pi 2 = \(π * 2)" // Interpolação de strings
|
||||
|
||||
// Constrói valores específicos
|
||||
// Utiliza configuração de build -D
|
||||
#if false
|
||||
println("Not printed")
|
||||
let buildValue = 3
|
||||
#else
|
||||
let buildValue = 7
|
||||
#endif
|
||||
println("Build value: \(buildValue)") // Build value: 7
|
||||
|
||||
/*
|
||||
Optionals fazem parte da linguagem e permitem que você armazene um
|
||||
valor `Some` (algo) ou `None` (nada).
|
||||
|
||||
Como Swift requer que todas as propriedades tenham valores, até mesmo nil deve
|
||||
ser explicitamente armazenado como um valor Optional.
|
||||
|
||||
Optional<T> é uma enum.
|
||||
*/
|
||||
var someOptionalString: String? = "optional" // Pode ser nil
|
||||
// o mesmo acima, mas ? é um operador pós-fixado (açúcar sintático)
|
||||
var someOptionalString2: Optional<String> = "optional"
|
||||
|
||||
if someOptionalString != nil {
|
||||
// Eu não sou nil
|
||||
if someOptionalString!.hasPrefix("opt") {
|
||||
println("has the prefix")
|
||||
}
|
||||
|
||||
let empty = someOptionalString?.isEmpty
|
||||
}
|
||||
someOptionalString = nil
|
||||
|
||||
// Optional implicitamente desempacotado (unwrapped)
|
||||
var unwrappedString: String! = "Valor é esperado."
|
||||
// o mesmo acima, mas ? é um operador pósfixado (açúcar sintático)
|
||||
var unwrappedString2: ImplicitlyUnwrappedOptional<String> = "Valor é esperado."
|
||||
|
||||
if let someOptionalStringConstant = someOptionalString {
|
||||
// Tem `Some` (algum) valor, não nil
|
||||
if !someOptionalStringConstant.hasPrefix("ok") {
|
||||
// não possui o prefixo
|
||||
}
|
||||
}
|
||||
|
||||
// Swift tem suporte para armazenar um valor de qualquer tipo.
|
||||
// AnyObject == id
|
||||
// Ao contrário de Objective-C `id`, AnyObject funciona com qualquer valor (Class, Int, struct, etc)
|
||||
var anyObjectVar: AnyObject = 7
|
||||
anyObjectVar = "Mudou o valor para string, não é uma boa prática, mas é possível."
|
||||
|
||||
/*
|
||||
Comentário aqui
|
||||
/*
|
||||
Comentários aninhados também são suportados
|
||||
*/
|
||||
*/
|
||||
|
||||
//
|
||||
// MARK: Coleções
|
||||
//
|
||||
|
||||
/*
|
||||
Tipos Array e Dicionário são structs. Portanto `let` e `var`
|
||||
também indicam se são mutáveis (var) ou imutáveis (let) quando declarados
|
||||
com esses tipos.
|
||||
*/
|
||||
|
||||
// Array
|
||||
var shoppingList = ["catfish", "water", "lemons"]
|
||||
shoppingList[1] = "bottle of water"
|
||||
let emptyArray = [String]() // imutável
|
||||
var emptyMutableArray = [String]() // mutável
|
||||
|
||||
|
||||
// Dicionário
|
||||
var occupations = [
|
||||
"Malcolm": "Captain",
|
||||
"kaylee": "Mechanic"
|
||||
]
|
||||
occupations["Jayne"] = "Public Relations"
|
||||
let emptyDictionary = [String: Float]() // imutável
|
||||
var emptyMutableDictionary = [String: Float]() // mutável
|
||||
|
||||
|
||||
//
|
||||
// MARK: Controle de fluxo
|
||||
//
|
||||
|
||||
// laço for (array)
|
||||
let myArray = [1, 1, 2, 3, 5]
|
||||
for value in myArray {
|
||||
if value == 1 {
|
||||
println("One!")
|
||||
} else {
|
||||
println("Not one!")
|
||||
}
|
||||
}
|
||||
|
||||
// laço for (dicionário)
|
||||
var dict = ["one": 1, "two": 2]
|
||||
for (key, value) in dict {
|
||||
println("\(key): \(value)")
|
||||
}
|
||||
|
||||
// laço for (alcance)
|
||||
for i in -1...shoppingList.count {
|
||||
println(i)
|
||||
}
|
||||
shoppingList[1...2] = ["steak", "peacons"]
|
||||
// use ..< para excluir o último número
|
||||
|
||||
// laço while (enquanto)
|
||||
var i = 1
|
||||
while i < 1000 {
|
||||
i *= 2
|
||||
}
|
||||
|
||||
// laço do-while
|
||||
do {
|
||||
println("hello")
|
||||
} while 1 == 2
|
||||
|
||||
// Switch
|
||||
let vegetable = "red pepper"
|
||||
switch vegetable {
|
||||
case "celery":
|
||||
let vegetableComment = "Add some raisins and make ants on a log."
|
||||
case "cucumber", "watercress":
|
||||
let vegetableComment = "That would make a good tea sandwich."
|
||||
case let x where x.hasSuffix("pepper"):
|
||||
let vegetableComment = "Is it a spicy \(x)?"
|
||||
default: // required (in order to cover all possible input)
|
||||
let vegetableComment = "Everything tastes good in soup."
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// MARK: Funções
|
||||
//
|
||||
|
||||
// Funções são tipos de primeira classe, o que significa que eles podem ser aninhados
|
||||
// em funções e podem ser passados como parâmetros
|
||||
|
||||
// Funções Swift com cabeçalhos doc (formato como reStructedText)
|
||||
/**
|
||||
Uma operação de saudação
|
||||
|
||||
- Um bullet em documentos
|
||||
- Outro bullet
|
||||
|
||||
:param: nome A nome
|
||||
:param: dia A dia
|
||||
:returns: Uma string contendo o nome e o dia.
|
||||
*/
|
||||
func greet(name: String, day: String) -> String {
|
||||
return "Hello \(name), today is \(day)."
|
||||
}
|
||||
greet("Bob", "Tuesday")
|
||||
|
||||
// Função que retorna múltiplos items em uma tupla
|
||||
func getGasPrices() -> (Double, Double, Double) {
|
||||
return (3.59, 3.69, 3.79)
|
||||
}
|
||||
let pricesTuple = getGasPrices()
|
||||
let price = pricesTuple.2 // 3.79
|
||||
// Ignore valores de Tuplas (ou outros valores) usando _ (underscore)
|
||||
let (_, price1, _) = pricesTuple // price1 == 3.69
|
||||
println(price1 == pricesTuple.1) // true
|
||||
println("Gas price: \(price)")
|
||||
|
||||
// Número variável de argumentos
|
||||
func setup(numbers: Int...) {
|
||||
// its an array
|
||||
let number = numbers[0]
|
||||
let argCount = numbers.count
|
||||
}
|
||||
|
||||
// Passando e retornando funções
|
||||
func makeIncrementer() -> (Int -> Int) {
|
||||
func addOne(number: Int) -> Int {
|
||||
return 1 + number
|
||||
}
|
||||
return addOne
|
||||
}
|
||||
var increment = makeIncrementer()
|
||||
increment(7)
|
||||
|
||||
// passagem por referência
|
||||
func swapTwoInts(inout a: Int, inout b: Int) {
|
||||
let tempA = a
|
||||
a = b
|
||||
b = tempA
|
||||
}
|
||||
var someIntA = 7
|
||||
var someIntB = 3
|
||||
swapTwoInts(&someIntA, &someIntB)
|
||||
println(someIntB) // 7
|
||||
|
||||
|
||||
//
|
||||
// MARK: Closures
|
||||
//
|
||||
var numbers = [1, 2, 6]
|
||||
|
||||
// Funções são casos especiais de closures ({})
|
||||
|
||||
// Exemplo de closure.
|
||||
// `->` separa argumentos e tipo de retorno
|
||||
// `in` separa o cabeçalho do closure do seu corpo
|
||||
numbers.map({
|
||||
(number: Int) -> Int in
|
||||
let result = 3 * number
|
||||
return result
|
||||
})
|
||||
|
||||
// Quando o tipo é conhecido, como abaixo, nós podemos fazer o seguinte
|
||||
numbers = numbers.map({ number in 3 * number })
|
||||
// Ou até mesmo isso
|
||||
//numbers = numbers.map({ $0 * 3 })
|
||||
|
||||
print(numbers) // [3, 6, 18]
|
||||
|
||||
// Closure restante
|
||||
numbers = sorted(numbers) { $0 > $1 }
|
||||
|
||||
print(numbers) // [18, 6, 3]
|
||||
|
||||
// Super atalho, já que o operador < infere os tipos
|
||||
|
||||
numbers = sorted(numbers, < )
|
||||
|
||||
print(numbers) // [3, 6, 18]
|
||||
|
||||
//
|
||||
// MARK: Estruturas
|
||||
//
|
||||
|
||||
// Estruturas e classes tem funcionalidades muito similares
|
||||
struct NamesTable {
|
||||
let names: [String]
|
||||
|
||||
// Custom subscript
|
||||
subscript(index: Int) -> String {
|
||||
return names[index]
|
||||
}
|
||||
}
|
||||
|
||||
// Estruturas possuem um inicializador auto-gerado automático (implícito)
|
||||
let namesTable = NamesTable(names: ["Me", "Them"])
|
||||
//let name = namesTable[2]
|
||||
//println("Name is \(name)") // Name is Them
|
||||
|
||||
//
|
||||
// MARK: Classes
|
||||
//
|
||||
|
||||
// Classes, Estruturas e seus membros possuem três níveis de modificadores de acesso
|
||||
// Eles são: internal (default), public, private
|
||||
|
||||
public class Shape {
|
||||
public func getArea() -> Int {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Todos os métodos e propriedades de uma classe são públicos.
|
||||
// Se você só precisa armazenar dados em um objeto estruturado, use `struct`
|
||||
|
||||
internal class Rect: Shape {
|
||||
var sideLength: Int = 1
|
||||
|
||||
// Getter e setter personalizado
|
||||
private var perimeter: Int {
|
||||
get {
|
||||
return 4 * sideLength
|
||||
}
|
||||
set {
|
||||
// `newValue` é uma variável implicita disponível para os setters
|
||||
sideLength = newValue / 4
|
||||
}
|
||||
}
|
||||
|
||||
// Carregue uma propriedade sob demanda (lazy)
|
||||
// subShape permanece nil (não inicializado) até seu getter ser chamado
|
||||
lazy var subShape = Rect(sideLength: 4)
|
||||
|
||||
// Se você não precisa de um getter e setter personalizado,
|
||||
// mas ainda quer roda código antes e depois de configurar
|
||||
// uma propriedade, você pode usar `willSet` e `didSet`
|
||||
var identifier: String = "defaultID" {
|
||||
// o argumento `willSet` será o nome da variável para o novo valor
|
||||
willSet(someIdentifier) {
|
||||
print(someIdentifier)
|
||||
}
|
||||
}
|
||||
|
||||
init(sideLength: Int) {
|
||||
self.sideLength = sideLength
|
||||
// sempre chame super.init por último quand inicializar propriedades personalizadas (custom)
|
||||
super.init()
|
||||
}
|
||||
|
||||
func shrink() {
|
||||
if sideLength > 0 {
|
||||
--sideLength
|
||||
}
|
||||
}
|
||||
|
||||
override func getArea() -> Int {
|
||||
return sideLength * sideLength
|
||||
}
|
||||
}
|
||||
|
||||
// Uma classe básica `Square` que estende `Rect`
|
||||
class Square: Rect {
|
||||
convenience init() {
|
||||
self.init(sideLength: 5)
|
||||
}
|
||||
}
|
||||
|
||||
var mySquare = Square()
|
||||
print(mySquare.getArea()) // 25
|
||||
mySquare.shrink()
|
||||
print(mySquare.sideLength) // 4
|
||||
|
||||
// Compara instâncias, não é o mesmo que == o qual compara objetos
|
||||
if mySquare === mySquare {
|
||||
println("Yep, it's mySquare")
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// MARK: Enums
|
||||
//
|
||||
|
||||
// Enums podem opcionalmente ser de um tipo específico ou não.
|
||||
// Podem conter métodos do mesmo jeito que classes.
|
||||
|
||||
enum Suit {
|
||||
case Spades, Hearts, Diamonds, Clubs
|
||||
func getIcon() -> String {
|
||||
switch self {
|
||||
case .Spades: return "♤"
|
||||
case .Hearts: return "♡"
|
||||
case .Diamonds: return "♢"
|
||||
case .Clubs: return "♧"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// MARK: Protocolos
|
||||
//
|
||||
|
||||
// `protocol` pode requerer que os tipos que se adequam tenham
|
||||
// propriedades de instância, métodos, operadores e subscripts.
|
||||
protocol ShapeGenerator {
|
||||
var enabled: Bool { get set }
|
||||
func buildShape() -> Shape
|
||||
}
|
||||
|
||||
// Protocolos declarados com @objc permitem funções opcionais,
|
||||
// que permitem verificar a confomidade
|
||||
@objc protocol TransformShape {
|
||||
optional func reshaped()
|
||||
optional func canReshape() -> Bool
|
||||
}
|
||||
|
||||
class MyShape: Rect {
|
||||
var delegate: TransformShape?
|
||||
|
||||
func grow() {
|
||||
sideLength += 2
|
||||
|
||||
if let allow = self.delegate?.canReshape?() {
|
||||
// test for delegate then for method
|
||||
// testa por delegação e então por método
|
||||
self.delegate?.reshaped?()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// MARK: Outros
|
||||
//
|
||||
|
||||
// `extension`s: Adicionam uma funcionalidade extra para um tipo já existente.
|
||||
|
||||
// Square agora "segue" o protocolo `Printable`
|
||||
extension Square: Printable {
|
||||
var description: String {
|
||||
return "Area: \(self.getArea()) - ID: \(self.identifier)"
|
||||
}
|
||||
}
|
||||
|
||||
println("Square: \(mySquare)")
|
||||
|
||||
// Você pode também estender tipos embutidos (built-in)
|
||||
extension Int {
|
||||
var customProperty: String {
|
||||
return "This is \(self)"
|
||||
}
|
||||
|
||||
func multiplyBy(num: Int) -> Int {
|
||||
return num * self
|
||||
}
|
||||
}
|
||||
|
||||
println(7.customProperty) // "This is 7"
|
||||
println(14.multiplyBy(2)) // 42
|
||||
|
||||
// Generics: Similar com Java e C#. Use a palavra-chave `where` para
|
||||
// especificar os requisitos do generics.
|
||||
|
||||
func findIndex<T: Equatable>(array: [T], valueToFind: T) -> Int? {
|
||||
for (index, value) in enumerate(array) {
|
||||
if value == valueToFind {
|
||||
return index
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
let foundAtIndex = findIndex([1, 2, 3, 4], 3)
|
||||
println(foundAtIndex == 2) // true
|
||||
|
||||
// Operadores:
|
||||
// Operadores personalizados (custom) podem começar com os seguintes caracteres:
|
||||
// / = - + * % < > ! & | ^ . ~
|
||||
// ou
|
||||
// Unicode math, símbolo, seta, e caracteres tipográficos ou de desenho.
|
||||
prefix operator !!! {}
|
||||
|
||||
// Um operador de prefixo que triplica o comprimento do lado do quadrado
|
||||
// quando usado
|
||||
prefix func !!! (inout shape: Square) -> Square {
|
||||
shape.sideLength *= 3
|
||||
return shape
|
||||
}
|
||||
|
||||
// valor atual
|
||||
println(mySquare.sideLength) // 4
|
||||
|
||||
// Troca o comprimento do lado usando um operador personalizado !!!, aumenta o lado por 3
|
||||
!!!mySquare
|
||||
println(mySquare.sideLength) // 12
|
||||
|
||||
```
|
@ -264,7 +264,7 @@ filled_dict.get("four") # => None
|
||||
# The get method supports a default argument when the value is missing
|
||||
filled_dict.get("one", 4) # => 1
|
||||
filled_dict.get("four", 4) # => 4
|
||||
# note that filled_dict.get("four") is still => 4
|
||||
# note that filled_dict.get("four") is still => None
|
||||
# (get doesn't set the value in the dictionary)
|
||||
|
||||
# set the value of a key with a syntax similar to lists
|
||||
|
@ -635,7 +635,6 @@ print(say(say_please=True)) # Can you buy me a beer? Please! I am poor :(
|
||||
|
||||
* [The Official Docs](http://docs.python.org/3/)
|
||||
* [Hitchhiker's Guide to Python](http://docs.python-guide.org/en/latest/)
|
||||
* [Python Module of the Week](http://pymotw.com/3/)
|
||||
* [A Crash Course in Python for Scientists](http://nbviewer.ipython.org/5920182)
|
||||
|
||||
### Dead Tree
|
||||
|
@ -65,7 +65,7 @@ func beyondHello() {
|
||||
learnTypes() // < y minutes, learn more!
|
||||
}
|
||||
|
||||
// Функция имеющая входные параметры и возврат нескольких значений.
|
||||
// Функция, имеющая входные параметры и возвращающая несколько значений.
|
||||
func learnMultiple(x, y int) (sum, prod int) {
|
||||
return x + y, x * y // Возврат двух значений.
|
||||
}
|
||||
|
425
ru-ru/lua-ru.html.markdown
Normal file
425
ru-ru/lua-ru.html.markdown
Normal file
@ -0,0 +1,425 @@
|
||||
---
|
||||
language: lua
|
||||
filename: learnlua-ru.lua
|
||||
contributors:
|
||||
- ["Tyler Neylon", "http://tylerneylon.com/"]
|
||||
translators:
|
||||
- ["Max Solomonov", "https://vk.com/solomonovmaksim"]
|
||||
- ["Max Truhonin", "https://vk.com/maximmax42"]
|
||||
- ["Konstantin Gromyko", "https://vk.com/id0x1765d79"]
|
||||
- ["Stanislav Gromov", "https://vk.com/id156354391"]
|
||||
lang: ru-ru
|
||||
---
|
||||
|
||||
```lua
|
||||
-- Два дефиса начинают однострочный комментарий.
|
||||
|
||||
--[[
|
||||
Добавление двух квадратных скобок
|
||||
делает комментарий многострочным.
|
||||
--]]
|
||||
--------------------------------------------------------------------------------
|
||||
-- 1. Переменные, циклы и условия.
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
num = 42 -- Все числа имеют тип double.
|
||||
-- Не волнуйтесь, в 64-битных double 52 бита
|
||||
-- отведено под хранение целой части числа;
|
||||
-- точность не является проблемой для
|
||||
-- целочисленных значений, занимающих меньше 52 бит.
|
||||
|
||||
s = 'walternate' -- Неизменные строки, как в Python.
|
||||
t = "Двойные кавычки также приветствуются"
|
||||
u = [[ Двойные квадратные скобки
|
||||
начинают и заканчивают
|
||||
многострочные значения.]]
|
||||
t = nil -- Удаляет определение переменной t; в Lua есть сборка мусора.
|
||||
|
||||
-- Блоки обозначаются ключевыми словами, такими как do/end:
|
||||
while num < 50 do
|
||||
num = num + 1 -- Операторов ++ и += нет.
|
||||
end
|
||||
|
||||
-- Ветвление "если":
|
||||
if num > 40 then
|
||||
print('больше 40')
|
||||
elseif s ~= 'walternate' then -- ~= обозначает "не равно".
|
||||
-- Проверка равенства это ==, как в Python; работает для строк.
|
||||
io.write('не больше 40\n') -- По умолчанию вывод в stdout.
|
||||
else
|
||||
-- По умолчанию переменные являются глобальными.
|
||||
thisIsGlobal = 5 -- Стиль CamelСase является общим.
|
||||
|
||||
-- Как сделать переменную локальной:
|
||||
local line = io.read() -- Считывает введённую строку.
|
||||
|
||||
-- Для конкатенации строк используется оператор .. :
|
||||
print('Зима пришла, ' .. line)
|
||||
end
|
||||
|
||||
-- Неопределённые переменные возвращают nil.
|
||||
-- Этот пример не является ошибочным:
|
||||
foo = anUnknownVariable -- Теперь foo = nil.
|
||||
|
||||
aBoolValue = false
|
||||
|
||||
-- Только значения nil и false являются ложными; 0 и '' являются истинными!
|
||||
if not aBoolValue then print('это значение ложно') end
|
||||
|
||||
-- Для 'or' и 'and' действует принцип "какой оператор дальше,
|
||||
-- тот и применяется". Это действует аналогично оператору a?b:c в C/js:
|
||||
ans = aBoolValue and 'yes' or 'no' --> 'no'
|
||||
|
||||
karlSum = 0
|
||||
for i = 1, 100 do -- Здесь указан диапазон, ограниченный с двух сторон.
|
||||
karlSum = karlSum + i
|
||||
end
|
||||
|
||||
-- Используйте "100, 1, -1" как нисходящий диапазон:
|
||||
fredSum = 0
|
||||
for j = 100, 1, -1 do fredSum = fredSum + j end
|
||||
|
||||
-- В основном, диапазон устроен так: начало, конец[, шаг].
|
||||
|
||||
-- Другая конструкция цикла:
|
||||
repeat
|
||||
print('путь будущего')
|
||||
num = num - 1
|
||||
until num == 0
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- 2. Функции.
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
function fib(n)
|
||||
if n < 2 then return n end
|
||||
return fib(n - 2) + fib(n - 1)
|
||||
end
|
||||
|
||||
-- Вложенные и анонимные функции являются нормой:
|
||||
function adder(x)
|
||||
-- Возращаемая функция создаётся, когда вызывается функция adder,
|
||||
-- и запоминает значение переменной x:
|
||||
return function (y) return x + y end
|
||||
end
|
||||
a1 = adder(9)
|
||||
a2 = adder(36)
|
||||
print(a1(16)) --> 25
|
||||
print(a2(64)) --> 100
|
||||
|
||||
-- Возвраты, вызовы функций и присвоения работают со списками,
|
||||
-- которые могут иметь разную длину.
|
||||
-- Лишние получатели принимают значение nil, а лишние значения игнорируются.
|
||||
|
||||
x, y, z = 1, 2, 3, 4
|
||||
-- Теперь x = 1, y = 2, z = 3, а 4 просто отбрасывается.
|
||||
|
||||
function bar(a, b, c)
|
||||
print(a, b, c)
|
||||
return 4, 8, 15, 16, 23, 42
|
||||
end
|
||||
|
||||
x, y = bar('zaphod') --> выводит "zaphod nil nil"
|
||||
-- Теперь x = 4, y = 8, а значения 15..42 отбрасываются.
|
||||
|
||||
-- Функции могут быть локальными и глобальными. Эти строки делают одно и то же:
|
||||
function f(x) return x * x end
|
||||
f = function (x) return x * x end
|
||||
|
||||
-- Эти тоже:
|
||||
local function g(x) return math.sin(x) end
|
||||
local g = function(x) return math.sin(x) end
|
||||
-- Эквивалентно для local function g(x)..., однако ссылки на g
|
||||
-- в теле функции не будут работать, как ожидалось.
|
||||
local g; g = function (x) return math.sin(x) end
|
||||
-- 'local g' будет прототипом функции.
|
||||
|
||||
-- Кстати, тригонометрические функции работают с радианами.
|
||||
|
||||
-- Вызов функции с одним строковым параметром не требует круглых скобок:
|
||||
print 'hello' -- Работает без ошибок.
|
||||
|
||||
-- Вызов функции с одним табличным параметром также
|
||||
-- не требует круглых скобок (про таблицы в след. части):
|
||||
print {} -- Тоже сработает.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- 3. Таблицы.
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Таблица = единственная составная структура данных в Lua;
|
||||
-- представляет собой ассоциативный массив.
|
||||
-- Подобно массивам в PHP или объектам в JS, они представляют собой
|
||||
-- хеш-таблицы, которые также можно использовать в качестве списков.
|
||||
|
||||
|
||||
-- Использование словарей:
|
||||
|
||||
-- Литералы имеют ключ по умолчанию:
|
||||
t = {key1 = 'value1', key2 = false}
|
||||
|
||||
-- Строковые ключи используются, как в точечной нотации в JS:
|
||||
print(t.key1) -- Печатает 'value1'.
|
||||
t.newKey = {} -- Добавляет новую пару ключ/значение.
|
||||
t.key2 = nil -- Удаляет key2 из таблицы.
|
||||
|
||||
-- Литеральная нотация для любого значения ключа (кроме nil):
|
||||
u = {['@!#'] = 'qbert', [{}] = 1729, [6.28] = 'tau'}
|
||||
print(u[6.28]) -- пишет "tau"
|
||||
|
||||
-- Ключ соответствует значению для чисел и строк, но при
|
||||
-- использовании таблицы в качестве ключа берётся её экземпляр.
|
||||
a = u['@!#'] -- Теперь a = 'qbert'.
|
||||
b = u[{}] -- Вы могли ожидать 1729, но получится nil:
|
||||
-- b = nil, т.к. ключ не будет найден.
|
||||
-- Это произойдёт потому, что за ключ мы использовали не тот же самый объект,
|
||||
-- который был использован для сохранения оригинального значения.
|
||||
-- Поэтому строки и числа удобнее использовать в качестве ключей.
|
||||
|
||||
-- Вызов функции с одной таблицей в качестве аргумента
|
||||
-- не требует круглых скобок:
|
||||
function h(x) print(x.key1) end
|
||||
h{key1 = 'Sonmi~451'} -- Печатает 'Sonmi~451'.
|
||||
|
||||
for key, val in pairs(u) do -- Цикл по таблице.
|
||||
print(key, val)
|
||||
end
|
||||
|
||||
-- _G - это таблица со всеми глобалями.
|
||||
print(_G['_G'] == _G) -- Печатает 'true'.
|
||||
|
||||
-- Использование таблиц, как списков / массивов:
|
||||
|
||||
-- Список значений с неявно заданными целочисленными ключами:
|
||||
v = {'value1', 'value2', 1.21, 'gigawatts'}
|
||||
for i = 1, #v do -- #v - размер списка v.
|
||||
print(v[i]) -- Нумерация начинается с 1 !!
|
||||
end
|
||||
|
||||
-- Список не является отдельным типом. v - всего лишь таблица
|
||||
-- с последовательными целочисленными ключами, воспринимаемая как список.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- 3.1 Метатаблицы и метаметоды.
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Таблицу можно связать с метатаблицей, задав ей поведение, как при
|
||||
-- перегрузке операторов. Позже мы увидим, что метатаблицы поддерживают
|
||||
-- поведение, как в js-прототипах.
|
||||
f1 = {a = 1, b = 2} -- Представляет дробь a/b.
|
||||
f2 = {a = 2, b = 3}
|
||||
|
||||
-- Это не сработает:
|
||||
-- s = f1 + f2
|
||||
|
||||
metafraction = {}
|
||||
function metafraction.__add(f1, f2)
|
||||
local sum = {}
|
||||
sum.b = f1.b * f2.b
|
||||
sum.a = f1.a * f2.b + f2.a * f1.b
|
||||
return sum
|
||||
end
|
||||
|
||||
setmetatable(f1, metafraction)
|
||||
setmetatable(f2, metafraction)
|
||||
|
||||
s = f1 + f2 -- вызвать __add(f1, f2) на метатаблице от f1
|
||||
|
||||
-- f1, f2 не имеют ключа для своих метатаблиц в отличии от прототипов в js,
|
||||
-- нужно получить его через getmetatable(f1). Метатаблица - обычная таблица
|
||||
-- поэтому с ключами, известными для Lua (например, __add).
|
||||
|
||||
-- Но следущая строка будет ошибочной т.к в s нет метатаблицы:
|
||||
-- t = s + s
|
||||
-- Похожий на классы подход, приведенный ниже, поможет это исправить.
|
||||
|
||||
-- __index перегружает в метатаблице просмотр через точку:
|
||||
defaultFavs = {animal = 'gru', food = 'donuts'}
|
||||
myFavs = {food = 'pizza'}
|
||||
setmetatable(myFavs, {__index = defaultFavs})
|
||||
eatenBy = myFavs.animal -- работает! спасибо, мета-таблица.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- При неудаче прямой табличный поиск попытается использовать
|
||||
-- значение __index в метатаблице, причём это рекурсивно.
|
||||
|
||||
-- Значение __index также может быть функцией
|
||||
-- function(tbl, key) для настраиваемого поиска.
|
||||
|
||||
-- Значения типа __index, __add, ... называются метаметодами.
|
||||
-- Ниже приведён полный список метаметодов.
|
||||
|
||||
-- __add(a, b) для a + b
|
||||
-- __sub(a, b) для a - b
|
||||
-- __mul(a, b) для a * b
|
||||
-- __div(a, b) для a / b
|
||||
-- __mod(a, b) для a % b
|
||||
-- __pow(a, b) для a ^ b
|
||||
-- __unm(a) для -a
|
||||
-- __concat(a, b) для a .. b
|
||||
-- __len(a) для #a
|
||||
-- __eq(a, b) для a == b
|
||||
-- __lt(a, b) для a < b
|
||||
-- __le(a, b) для a <= b
|
||||
-- __index(a, b) <функция или таблица> для a.b
|
||||
-- __newindex(a, b, c) для a.b = c
|
||||
-- __call(a, ...) для a(...)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- 3.2 Классоподобные таблицы и наследование.
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- В Lua нет поддержки классов на уровне языка,
|
||||
-- однако существуют разные способы их создания с помощью
|
||||
-- таблиц и метатаблиц.
|
||||
|
||||
-- Ниже приведён один из таких способов.
|
||||
|
||||
Dog = {} -- 1.
|
||||
|
||||
function Dog:new() -- 2.
|
||||
local 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 похоже на класс, но на самом деле это таблица.
|
||||
-- 2. "function tablename:fn(...)" - то же самое, что и
|
||||
-- "function tablename.fn(self, ...)", просто : добавляет первый аргумент
|
||||
-- перед собой. См. пункты 7 и 8, чтобы понять, как self получает значение.
|
||||
-- 3. newObj - это экземпляр класса Dog.
|
||||
-- 4. "self" - экземпляр класса. Зачастую self = Dog, но с помощью наследования
|
||||
-- это можно изменить. newObj получит свои функции, когда мы установим
|
||||
-- метатаблицу для newObj и __index для self на саму себя.
|
||||
-- 5. Напоминание: setmetatable возвращает первый аргумент.
|
||||
-- 6. : работает, как в пункте 2, но в этот раз мы ожидаем,
|
||||
-- что self будет экземпляром, а не классом.
|
||||
-- 7. То же самое, что и Dog.new(Dog), поэтому self = Dog в new().
|
||||
-- 8. То же самое, что mrDog.makeSound(mrDog); self = mrDog.
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Пример наследования:
|
||||
|
||||
LoudDog = Dog:new() -- 1.
|
||||
|
||||
function LoudDog:makeSound()
|
||||
local s = self.sound .. ' ' -- 2.
|
||||
print(s .. s .. s)
|
||||
end
|
||||
|
||||
seymour = LoudDog:new() -- 3.
|
||||
seymour:makeSound() -- 'woof woof woof' -- 4.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- 1. LoudDog получит методы и переменные класса Dog.
|
||||
-- 2. В self будет ключ 'sound' из new(), см. пункт 3.
|
||||
-- 3. То же самое, что и "LoudDog.new(LoudDog)", конвертированное
|
||||
-- в "Dog.new(LoudDog)", поскольку в LoudDog нет ключа 'new',
|
||||
-- но в его метатаблице есть "__index = Dog".
|
||||
-- Результат: Метатаблицей для seymour стала LoudDog,
|
||||
-- а "LoudDog.__index = Dog". Поэтому seymour.key будет равно
|
||||
-- seymour.key, LoudDog.key, Dog.key, в зависимости от того,
|
||||
-- какая таблица будет первой с заданным ключом.
|
||||
-- 4. Ключ 'makeSound' находится в LoudDog;
|
||||
-- то же самое, что и "LoudDog.makeSound(seymour)".
|
||||
|
||||
-- При необходимости функция new() в подклассе
|
||||
-- может быть похожа на аналог в базовом классе.
|
||||
function LoudDog:new()
|
||||
local newObj = {}
|
||||
-- установить newObj
|
||||
self.__index = self
|
||||
return setmetatable(newObj, self)
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- 4. Модули.
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
--[[ Я закомментировал этот раздел, чтобы остальная часть скрипта осталась
|
||||
-- работоспособной.
|
||||
```
|
||||
|
||||
```lua
|
||||
-- Предположим, файл mod.lua будет выглядеть так:
|
||||
local M = {}
|
||||
|
||||
local function sayMyName()
|
||||
print('Hrunkner')
|
||||
end
|
||||
|
||||
function M.sayHello()
|
||||
print('Привет, ')
|
||||
sayMyName()
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
-- Другой файл может использовать функционал mod.lua:
|
||||
local mod = require('mod') -- Запустим файл mod.lua.
|
||||
|
||||
-- require - стандартный способ подключения модулей.
|
||||
-- require ведёт себя так: (если не кэшировано, см. ниже)
|
||||
local mod = (function ()
|
||||
<содержимое mod.lua>
|
||||
end)()
|
||||
-- Файл mod.lua воспринимается, как тело функции, поэтому
|
||||
-- все локальные переменные и функции внутри него не видны за его пределами.
|
||||
|
||||
-- Это работает, так как здесь mod = M в mod.lua:
|
||||
mod.sayHello() -- Выведет "Привет, Hrunkner".
|
||||
|
||||
-- Это будет ошибочным; sayMyName доступна только в mod.lua:
|
||||
mod.sayMyName() -- ошибка
|
||||
|
||||
-- Значения, возвращаемые require, кэшируются,
|
||||
-- поэтому содержимое файла выполняется только 1 раз,
|
||||
-- даже если он подключается с помощью require много раз.
|
||||
|
||||
-- Предположим, mod2.lua содержит "print('Hi!')".
|
||||
local a = require('mod2') -- Выведет "Hi!"
|
||||
local b = require('mod2') -- Ничего не выведет; a=b.
|
||||
|
||||
-- dofile, в отличии от require, работает без кэширования:
|
||||
dofile('mod2') --> Hi!
|
||||
dofile('mod2') --> Hi! (запустится снова)
|
||||
|
||||
-- loadfile загружает файл, но не запускает его.
|
||||
f = loadfile('mod2') -- Вызов f() запустит содержимое mod2.lua.
|
||||
|
||||
-- loadstring - это loadfile для строк.
|
||||
g = loadstring('print(343)') -- Вернет функцию.
|
||||
g() -- Напишет 343.
|
||||
|
||||
--]]
|
||||
|
||||
```
|
||||
## Примечание (от автора)
|
||||
|
||||
Мне было интересно изучить Lua, чтобы делать игры при помощи <a href="http://love2d.org/">игрового движка LÖVE</a>.
|
||||
|
||||
Я начинал с <a href="http://nova-fusion.com/2012/08/27/lua-for-programmers-part-1/">BlackBulletIV's Lua for programmers</a>.
|
||||
Затем я прочитал официальную <a href="http://www.lua.org/pil/contents.html">Документацию по Lua</a>.
|
||||
|
||||
Также может быть полезной <a href="http://lua-users.org/files/wiki_insecure/users/thomasl/luarefv51.pdf">Краткая справка по Lua</a> на lua-users.org.
|
||||
|
||||
Ещё из основных тем не охвачены стандартные библиотеки:
|
||||
|
||||
* <a href="http://lua-users.org/wiki/StringLibraryTutorial">библиотека string</a>
|
||||
* <a href="http://lua-users.org/wiki/TableLibraryTutorial">библиотека table</a>
|
||||
* <a href="http://lua-users.org/wiki/MathLibraryTutorial">библиотека math</a>
|
||||
* <a href="http://lua-users.org/wiki/IoLibraryTutorial">библиотека io</a>
|
||||
* <a href="http://lua-users.org/wiki/OsLibraryTutorial">библиотека os</a>
|
||||
|
||||
Кстати, весь файл написан на Lua; сохраните его как learn.lua и запустите при помощи "lua learn.lua" !
|
||||
|
||||
Изначально эта статья была написана для tylerneylon.com.
|
||||
Также она доступна как <a href="https://gist.github.com/tylerneylon/5853042">github gist</a>. Удачи с Lua!
|
@ -198,8 +198,10 @@ weirdSum(2, 4) // => 16
|
||||
|
||||
|
||||
// The return keyword exists in Scala, but it only returns from the inner-most
|
||||
// def that surrounds it. It has no effect on anonymous functions. For example:
|
||||
def foo(x: Int) = {
|
||||
// def that surrounds it.
|
||||
// WARNING: Using return in Scala is error-prone and should be avoided.
|
||||
// It has no effect on anonymous functions. For example:
|
||||
def foo(x: Int): Int = {
|
||||
val anonFunc: Int => Int = { z =>
|
||||
if (z > 5)
|
||||
return z // This line makes z the return value of foo!
|
||||
@ -405,41 +407,55 @@ val otherGeorge = george.copy(phoneNumber = "9876")
|
||||
// 6. Pattern Matching
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
val me = Person("George", "1234")
|
||||
// Pattern matching is a powerful and commonly used feature in Scala. Here's how
|
||||
// you pattern match a case class. NB: Unlike other languages, Scala cases do
|
||||
// not need breaks, fall-through does not happen.
|
||||
|
||||
me match { case Person(name, number) => {
|
||||
"We matched someone : " + name + ", phone : " + number }}
|
||||
|
||||
me match { case Person(name, number) => "Match : " + name; case _ => "Hm..." }
|
||||
|
||||
me match { case Person("George", number) => "Match"; case _ => "Hm..." }
|
||||
|
||||
me match { case Person("Kate", number) => "Match"; case _ => "Hm..." }
|
||||
|
||||
me match { case Person("Kate", _) => "Girl"; case Person("George", _) => "Boy" }
|
||||
|
||||
val kate = Person("Kate", "1234")
|
||||
|
||||
kate match { case Person("Kate", _) => "Girl"; case Person("George", _) => "Boy" }
|
||||
|
||||
|
||||
|
||||
// Regular expressions
|
||||
val email = "(.*)@(.*)".r // Invoking r on String makes it a Regex
|
||||
val serialKey = """(\d{5})-(\d{5})-(\d{5})-(\d{5})""".r // Using verbatim (multiline) syntax
|
||||
|
||||
val matcher = (value: String) => {
|
||||
println(value match {
|
||||
case email(name, domain) => s"It was an email: $name"
|
||||
case serialKey(p1, p2, p3, p4) => s"Serial key: $p1, $p2, $p3, $p4"
|
||||
case _ => s"No match on '$value'" // default if no match found
|
||||
})
|
||||
def matchPerson(person: Person): String = person match {
|
||||
// Then you specify the patterns:
|
||||
case Person("George", number) => "We found George! His number is " + number
|
||||
case Person("Kate", number) => "We found Kate! Her number is " + number
|
||||
case Person(name, number) => "We matched someone : " + name + ", phone : " + number
|
||||
}
|
||||
|
||||
matcher("mrbean@pyahoo.com") // => "It was an email: mrbean"
|
||||
matcher("nope..") // => "No match on 'nope..'"
|
||||
matcher("52917") // => "No match on '52917'"
|
||||
matcher("52752-16432-22178-47917") // => "Serial key: 52752, 16432, 22178, 47917"
|
||||
val email = "(.*)@(.*)".r // Define a regex for the next example.
|
||||
|
||||
// Pattern matching might look familiar to the switch statements in the C family
|
||||
// of languages, but this is much more powerful. In Scala, you can match much
|
||||
// more:
|
||||
def matchEverything(obj: Any): String = obj match {
|
||||
// You can match values:
|
||||
case "Hello world" => "Got the string Hello world"
|
||||
|
||||
// You can match by type:
|
||||
case x: Double => "Got a Double: " + x
|
||||
|
||||
// You can specify conditions:
|
||||
case x: Int if x > 10000 => "Got a pretty big number!"
|
||||
|
||||
// You can match case classes as before:
|
||||
case Person(name, number) => s"Got contact info for $name!"
|
||||
|
||||
// You can match regular expressions:
|
||||
case email(name, domain) => s"Got email address $name@$domain"
|
||||
|
||||
// You can match tuples:
|
||||
case (a: Int, b: Double, c: String) => s"Got a tuple: $a, $b, $c"
|
||||
|
||||
// You can match data structures:
|
||||
case List(1, b, c) => s"Got a list with three elements and starts with 1: 1, $b, $c"
|
||||
|
||||
// You can nest patterns:
|
||||
case List(List((1, 2,"YAY"))) => "Got a list of list of tuple"
|
||||
}
|
||||
|
||||
// In fact, you can pattern match any object with an "unapply" method. This
|
||||
// feature is so powerful that Scala lets you define whole functions as
|
||||
// patterns:
|
||||
val patternFunc: Person => String = {
|
||||
case Person("George", number") => s"George's number: $number"
|
||||
case Person(name, number) => s"Random person's number: $number"
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
@ -476,7 +492,7 @@ sSquared.reduce (_+_)
|
||||
// The filter function takes a predicate (a function from A -> Boolean) and
|
||||
// selects all elements which satisfy the predicate
|
||||
List(1, 2, 3) filter (_ > 2) // List(3)
|
||||
case class Person(name:String, phoneNumber:String)
|
||||
case class Person(name:String, age:Int)
|
||||
List(
|
||||
Person(name = "Dom", age = 23),
|
||||
Person(name = "Bob", age = 30)
|
||||
|
@ -6,7 +6,7 @@ contributors:
|
||||
filename: learnswift.swift
|
||||
---
|
||||
|
||||
Swift is a programming language for iOS and OS X development created by Apple. Designed to coexist with Objective-C and to be more resilient against erroneous code, Swift was introduced in 2014 at Apple's developer conference WWDC. It is built with the LLVM compiler included in Xcode 6 beta.
|
||||
Swift is a programming language for iOS and OS X development created by Apple. Designed to coexist with Objective-C and to be more resilient against erroneous code, Swift was introduced in 2014 at Apple's developer conference WWDC. It is built with the LLVM compiler included in Xcode 6+.
|
||||
|
||||
The official [Swift Programming Language](https://itunes.apple.com/us/book/swift-programming-language/id881256329) book from Apple is now available via iBooks.
|
||||
|
||||
@ -23,7 +23,7 @@ import UIKit
|
||||
// Xcode supports landmarks to annotate your code and lists them in the jump bar
|
||||
// MARK: Section mark
|
||||
// TODO: Do something soon
|
||||
// FIXME Fix this code
|
||||
// FIXME: Fix this code
|
||||
|
||||
println("Hello, world")
|
||||
|
||||
@ -55,8 +55,8 @@ println("Build value: \(buildValue)") // Build value: 7
|
||||
/*
|
||||
Optionals are a Swift language feature that allows you to store a `Some` or
|
||||
`None` value.
|
||||
|
||||
Because Swift requires every property to have a value, even nil must be
|
||||
|
||||
Because Swift requires every property to have a value, even nil must be
|
||||
explicitly stored as an Optional value.
|
||||
|
||||
Optional<T> is an enum.
|
||||
@ -94,7 +94,8 @@ var anyObjectVar: AnyObject = 7
|
||||
anyObjectVar = "Changed value to a string, not good practice, but possible."
|
||||
|
||||
/*
|
||||
Comment here
|
||||
Comment here
|
||||
|
||||
/*
|
||||
Nested comments are also supported
|
||||
*/
|
||||
@ -112,8 +113,9 @@ Comment here
|
||||
// Array
|
||||
var shoppingList = ["catfish", "water", "lemons"]
|
||||
shoppingList[1] = "bottle of water"
|
||||
let emptyArray = [String]() // immutable
|
||||
var emptyMutableArray = [String]() // mutable
|
||||
let emptyArray = [String]() // let == immutable
|
||||
let emptyArray2 = Array<String>() // same as above
|
||||
var emptyMutableArray = [String]() // var == mutable
|
||||
|
||||
|
||||
// Dictionary
|
||||
@ -122,8 +124,9 @@ var occupations = [
|
||||
"kaylee": "Mechanic"
|
||||
]
|
||||
occupations["Jayne"] = "Public Relations"
|
||||
let emptyDictionary = [String: Float]() // immutable
|
||||
var emptyMutableDictionary = [String: Float]() // mutable
|
||||
let emptyDictionary = [String: Float]() // let == immutable
|
||||
let emptyDictionary2 = Dictionary<String, Float>() // same as above
|
||||
var emptyMutableDictionary = [String: Float]() // var == mutable
|
||||
|
||||
|
||||
//
|
||||
@ -165,14 +168,16 @@ do {
|
||||
} while 1 == 2
|
||||
|
||||
// Switch
|
||||
// Very powerful, think `if` statements with syntax candy
|
||||
// They support String, object instances, and primitives (Int, Double, etc)
|
||||
let vegetable = "red pepper"
|
||||
switch vegetable {
|
||||
case "celery":
|
||||
let vegetableComment = "Add some raisins and make ants on a log."
|
||||
case "cucumber", "watercress":
|
||||
let vegetableComment = "That would make a good tea sandwich."
|
||||
case let x where x.hasSuffix("pepper"):
|
||||
let vegetableComment = "Is it a spicy \(x)?"
|
||||
case let localScopeValue where localScopeValue.hasSuffix("pepper"):
|
||||
let vegetableComment = "Is it a spicy \(localScopeValue)?"
|
||||
default: // required (in order to cover all possible input)
|
||||
let vegetableComment = "Everything tastes good in soup."
|
||||
}
|
||||
@ -186,21 +191,28 @@ default: // required (in order to cover all possible input)
|
||||
// in functions and can be passed around
|
||||
|
||||
// Function with Swift header docs (format as reStructedText)
|
||||
|
||||
/**
|
||||
A greet operation
|
||||
A greet operation
|
||||
|
||||
- A bullet in docs
|
||||
- Another bullet in the docs
|
||||
- A bullet in docs
|
||||
- Another bullet in the docs
|
||||
|
||||
:param: name A name
|
||||
:param: day A day
|
||||
:returns: A string containing the name and day value.
|
||||
:param: name A name
|
||||
:param: day A day
|
||||
:returns: A string containing the name and day value.
|
||||
*/
|
||||
func greet(name: String, day: String) -> String {
|
||||
return "Hello \(name), today is \(day)."
|
||||
}
|
||||
greet("Bob", "Tuesday")
|
||||
|
||||
// similar to above except for the function parameter behaviors
|
||||
func greet2(#requiredName: String, externalParamName localParamName: String) -> String {
|
||||
return "Hello \(requiredName), the day is \(localParamName)"
|
||||
}
|
||||
greet2(requiredName:"John", externalParamName: "Sunday")
|
||||
|
||||
// Function that returns multiple items in a tuple
|
||||
func getGasPrices() -> (Double, Double, Double) {
|
||||
return (3.59, 3.69, 3.79)
|
||||
@ -281,7 +293,7 @@ print(numbers) // [3, 6, 18]
|
||||
|
||||
// Structures and classes have very similar capabilites
|
||||
struct NamesTable {
|
||||
let names: [String]
|
||||
let names = [String]()
|
||||
|
||||
// Custom subscript
|
||||
subscript(index: Int) -> String {
|
||||
@ -291,8 +303,8 @@ struct NamesTable {
|
||||
|
||||
// Structures have an auto-generated (implicit) designated initializer
|
||||
let namesTable = NamesTable(names: ["Me", "Them"])
|
||||
//let name = namesTable[2]
|
||||
//println("Name is \(name)") // Name is Them
|
||||
let name = namesTable[1]
|
||||
println("Name is \(name)") // Name is Them
|
||||
|
||||
//
|
||||
// MARK: Classes
|
||||
@ -341,7 +353,7 @@ internal class Rect: Shape {
|
||||
|
||||
init(sideLength: Int) {
|
||||
self.sideLength = sideLength
|
||||
// always super.init last when init custom properties
|
||||
// always super.init last when init custom properties
|
||||
super.init()
|
||||
}
|
||||
|
||||
@ -368,6 +380,9 @@ print(mySquare.getArea()) // 25
|
||||
mySquare.shrink()
|
||||
print(mySquare.sideLength) // 4
|
||||
|
||||
// cast instance
|
||||
let aShape = mySquare as Shape
|
||||
|
||||
// compare instances, not the same as == which compares objects (equal to)
|
||||
if mySquare === mySquare {
|
||||
println("Yep, it's mySquare")
|
||||
@ -393,6 +408,17 @@ enum Suit {
|
||||
}
|
||||
}
|
||||
|
||||
// Enum values allow short hand syntax, no need to type the enum type
|
||||
// when the variable is explicitly declared
|
||||
var suitValue: Suit = .Hearts
|
||||
|
||||
// Non-Integer enums require direct raw value assignments
|
||||
enum BookName: String {
|
||||
case John = "John"
|
||||
case Luke = "Luke"
|
||||
}
|
||||
println("Name: \(BookName.John.rawValue)")
|
||||
|
||||
|
||||
//
|
||||
// MARK: Protocols
|
||||
@ -490,5 +516,4 @@ println(mySquare.sideLength) // 4
|
||||
// change side length using custom !!! operator, increases size by 3
|
||||
!!!mySquare
|
||||
println(mySquare.sideLength) // 12
|
||||
|
||||
```
|
||||
|
447
tcl.html.markdown
Executable file
447
tcl.html.markdown
Executable file
@ -0,0 +1,447 @@
|
||||
---
|
||||
language: Tcl
|
||||
contributors:
|
||||
- ["Poor Yorick", "http://pooryorick.com/"]
|
||||
filename: learntcl.tcl
|
||||
---
|
||||
|
||||
Tcl was created by [John Ousterhout](http://wiki.tcl.tk/John Ousterout) as a
|
||||
reusable scripting language for chip design tools he was creating. In 1997 he
|
||||
was awarded the [ACM Software System
|
||||
Award](http://en.wikipedia.org/wiki/ACM_Software_System_Award) for Tcl. Tcl
|
||||
can be used both as an embeddable scripting language and as a general
|
||||
programming language. It can also be used as a portable C library, even in
|
||||
cases where no scripting capability is needed, as it provides data structures
|
||||
such as dynamic strings, lists, and hash tables. The C library also provides
|
||||
portable functionality for loading dynamic libraries, string formatting and
|
||||
code conversion, filesystem operations, network operations, and more.
|
||||
Various features of Tcl stand out:
|
||||
|
||||
* Convenient cross-platform networking API
|
||||
|
||||
* Fully virtualized filesystem
|
||||
|
||||
* Stackable I/O channels
|
||||
|
||||
* Asynchronous to the core
|
||||
|
||||
* Full coroutines
|
||||
|
||||
* A threading model recognized as robust and easy to use
|
||||
|
||||
|
||||
If Lisp is a list processor, then Tcl is a string processor. All values are
|
||||
strings. A list is a string format. A procedure definition is a string
|
||||
format. To achieve performance, Tcl internally caches structured
|
||||
representations of these values. The list commands, for example, operate on
|
||||
the internal cached representation, and Tcl takes care of updating the string
|
||||
representation if it is ever actually needed in the script. The copy-on-write
|
||||
design of Tcl allows script authors can pass around large data values without
|
||||
actually incurring additional memory overhead. Procedures are automatically
|
||||
byte-compiled unless they use the more dynamic commands such as "uplevel",
|
||||
"upvar", and "trace".
|
||||
|
||||
Tcl is a pleasure to program in. It will appeal to hacker types who find Lisp,
|
||||
Forth, or Smalltalk interesting, as well as to engineers and scientists who
|
||||
just want to get down to business with a tool that bends to their will. Its
|
||||
discipline of exposing all programmatic functionality as commands, including
|
||||
things like loops and mathematical operations that are usually baked into the
|
||||
syntax of other languages, allows it to fade into the background of whatever
|
||||
domain-specific functionality a project needs. It's syntax, which is even
|
||||
lighter that that of Lisp, just gets out of the way.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```tcl
|
||||
#! /bin/env tclsh
|
||||
|
||||
################################################################################
|
||||
## 1. Guidelines
|
||||
################################################################################
|
||||
|
||||
# Tcl is not Bash or C! This needs to be said because standard shell quoting
|
||||
# habits almost work in Tcl and it is common for people to pick up Tcl and try
|
||||
# to get by with syntax they know from another language. It works at first,
|
||||
# but soon leads to frustration with more complex scripts.
|
||||
|
||||
# Braces are just a quoting mechanism, not a code block constructor or a list
|
||||
# constructor. Tcl doesn't have either of those things. Braces are used,
|
||||
# though, to escape special characters in procedure bodies and in strings that
|
||||
# are formatted as lists.
|
||||
|
||||
|
||||
################################################################################
|
||||
## 2. Syntax
|
||||
################################################################################
|
||||
|
||||
# Every line is a command. The first word is the name of the command, and
|
||||
# subsequent words are arguments to the command. Words are delimited by
|
||||
# whitespace. Since every word is a string, in the simple case no special
|
||||
# markup such as quotes, braces, or backslash, is necessary. Even when quotes
|
||||
# are used, they are not a string constructor, but just another escaping
|
||||
# character.
|
||||
|
||||
set greeting1 Sal
|
||||
set greeting2 ut
|
||||
set greeting3 ations
|
||||
|
||||
|
||||
#semicolon also delimits commands
|
||||
set greeting1 Sal; set greeting2 ut; set greeting3 ations
|
||||
|
||||
|
||||
# Dollar sign introduces variable substitution
|
||||
set greeting $greeting1$greeting2$greeting3
|
||||
|
||||
|
||||
# Bracket introduces command substitution. The result of the command is
|
||||
# substituted in place of the bracketed script. When the "set" command is
|
||||
# given only the name of a variable, it returns the value of that variable.
|
||||
set greeting $greeting1$greeting2[set greeting3]
|
||||
|
||||
|
||||
# Command substitution should really be called script substitution, because an
|
||||
# entire script, not just a command, can be placed between the brackets. The
|
||||
# "incr" command increments the value of a variable and returns its value.
|
||||
set greeting $greeting[
|
||||
incr i
|
||||
incr i
|
||||
incr i
|
||||
]
|
||||
|
||||
|
||||
# backslash suppresses the special meaning of characters
|
||||
set amount \$16.42
|
||||
|
||||
|
||||
# backslash adds special meaning to certain characters
|
||||
puts lots\nof\n\n\n\n\n\nnewlines
|
||||
|
||||
|
||||
# A word enclosed in braces is not subject to any special interpretation or
|
||||
# substitutions, except that a backslash before a brace is not counted when look#ing for the closing brace
|
||||
set somevar {
|
||||
This is a literal $ sign, and this \} escaped
|
||||
brace remains uninterpreted
|
||||
}
|
||||
|
||||
|
||||
# In a word enclosed in double quotes, whitespace characters lose their special
|
||||
# meaning
|
||||
set name Neo
|
||||
set greeting "Hello, $name"
|
||||
|
||||
|
||||
#variable names can be any string
|
||||
set {first name} New
|
||||
|
||||
|
||||
# The brace form of variable substitution handles more complex variable names
|
||||
set greeting "Hello, ${first name}"
|
||||
|
||||
|
||||
# The "set" command can always be used instead of variable substitution
|
||||
set greeting "Hello, [set {first name}]"
|
||||
|
||||
|
||||
# To promote the words within a word to individual words of the current
|
||||
# command, use the expansion operator, "{*}".
|
||||
set {*}{name Neo}
|
||||
|
||||
# is equivalent to
|
||||
set name Neo
|
||||
|
||||
|
||||
# An array is a special variable that is a container for other variables.
|
||||
set person(name) Neo
|
||||
set person(gender) male
|
||||
set greeting "Hello, $person(name)"
|
||||
|
||||
|
||||
# A namespace holds commands and variables
|
||||
namespace eval people {
|
||||
namespace eval person1 {
|
||||
set name Neo
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#The full name of a variable includes its enclosing namespace(s), delimited by two colons:
|
||||
set greeting "Hello $people::person::name"
|
||||
|
||||
|
||||
|
||||
################################################################################
|
||||
## 3. A Few Notes
|
||||
################################################################################
|
||||
|
||||
# All other functionality is implemented via commands. From this point on,
|
||||
# there is no new syntax. Everything else there is to learn about Tcl is about
|
||||
# the behaviour of individual commands, and what meaning they assign to their
|
||||
# arguments.
|
||||
|
||||
|
||||
# To end up with an interpreter that can do nothing, delete the global
|
||||
# namespace. It's not very useful to do such a thing, but it illustrates the
|
||||
# nature of Tcl.
|
||||
namespace delete ::
|
||||
|
||||
|
||||
# Because of name resolution behaviour, its safer to use the "variable" command to declare or to assign a value to a namespace.
|
||||
namespace eval people {
|
||||
namespace eval person1 {
|
||||
variable name Neo
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# The full name of a variable can always be used, if desired.
|
||||
set people::person1::name Neo
|
||||
|
||||
|
||||
|
||||
################################################################################
|
||||
## 4. Commands
|
||||
################################################################################
|
||||
|
||||
# Math can be done with the "expr" command.
|
||||
set a 3
|
||||
set b 4
|
||||
set c [expr {$a + $b}]
|
||||
|
||||
# Since "expr" performs variable substitution on its own, brace the expression
|
||||
# to prevent Tcl from performing variable substitution first. See
|
||||
# "http://wiki.tcl.tk/Brace%20your%20#%20expr-essions" for details.
|
||||
|
||||
|
||||
# The "expr" command understands variable and command substitution
|
||||
set c [expr {$a + [set b]}]
|
||||
|
||||
|
||||
# The "expr" command provides a set of mathematical functions
|
||||
set c [expr {pow($a,$b)}]
|
||||
|
||||
|
||||
# Mathematical operators are available as commands in the ::tcl::mathop
|
||||
# namespace
|
||||
::tcl::mathop::+ 5 3
|
||||
|
||||
# Commands can be imported from other namespaces
|
||||
namespace import ::tcl::mathop::+
|
||||
set result [+ 5 3]
|
||||
|
||||
|
||||
# New commands can be created via the "proc" command.
|
||||
proc greet name {
|
||||
return "Hello, $name!"
|
||||
}
|
||||
|
||||
#multiple parameters can be specified
|
||||
proc greet {greeting name} {
|
||||
return "$greeting, $name!"
|
||||
}
|
||||
|
||||
|
||||
# As noted earlier, braces do not construct a code block. Every value, even
|
||||
# the third argument of the "proc" command, is a string. The previous command
|
||||
# rewritten to not use braces at all:
|
||||
proc greet greeting\ name return\ \"Hello,\ \$name!
|
||||
|
||||
|
||||
|
||||
# When the last parameter is the literal value, "args", it collects all extra
|
||||
# arguments when the command is invoked
|
||||
proc fold {cmd args} {
|
||||
set res 0
|
||||
foreach arg $args {
|
||||
set res [cmd $res $arg]
|
||||
}
|
||||
}
|
||||
fold ::tcl::mathop::* 5 3 3 ;# -> 45
|
||||
|
||||
|
||||
# Conditional execution is implemented as a command
|
||||
if {3 > 4} {
|
||||
puts {This will never happen}
|
||||
} elseif {4 > 4} {
|
||||
puts {This will also never happen}
|
||||
} else {
|
||||
puts {This will always happen}
|
||||
}
|
||||
|
||||
|
||||
# Loops are implemented as commands. The first, second, and third
|
||||
# arguments of the "for" command are treated as mathematical expressions
|
||||
for {set i 0} {$i < 10} {incr i} {
|
||||
set res [expr {$res + $i}]
|
||||
}
|
||||
|
||||
|
||||
# The first argument of the "while" command is also treated as a mathematical
|
||||
# expression
|
||||
set i 0
|
||||
while {$i < 10} {
|
||||
incr i 2
|
||||
}
|
||||
|
||||
|
||||
# A list is a specially-formatted string. In the simple case, whitespace is sufficient to delimit values
|
||||
set amounts 10\ 33\ 18
|
||||
set amount [lindex $amounts 1]
|
||||
|
||||
|
||||
# Braces and backslash can be used to format more complex values in a list. A
|
||||
# list looks exactly like a script, except that the newline character and the
|
||||
# semicolon character lose their special meanings. This feature makes Tcl
|
||||
# homoiconic. There are three items in the following list.
|
||||
set values {
|
||||
|
||||
one\ two
|
||||
|
||||
{three four}
|
||||
|
||||
five\{six
|
||||
|
||||
}
|
||||
|
||||
|
||||
# Since a list is a string, string operations could be performed on it, at the
|
||||
# risk of corrupting the formatting of the list.
|
||||
set values {one two three four}
|
||||
set values [string map {two \{} $values] ;# $values is no-longer a \
|
||||
properly-formatted listwell-formed list
|
||||
|
||||
|
||||
# The sure-fire way to get a properly-formmated list is to use "list" commands
|
||||
set values [list one \{ three four]
|
||||
lappend values { } ;# add a single space as an item in the list
|
||||
|
||||
|
||||
# Use "eval" to evaluate a value as a script
|
||||
eval {
|
||||
set name Neo
|
||||
set greeting "Hello, $name"
|
||||
}
|
||||
|
||||
|
||||
# A list can always be passed to "eval" as a script composed of a single
|
||||
# command.
|
||||
eval {set name Neo}
|
||||
eval [list set greeting "Hello, $name"]
|
||||
|
||||
|
||||
# Therefore, when using "eval", use [list] to build up a desired command
|
||||
set command {set name}
|
||||
lappend command {Archibald Sorbisol}
|
||||
eval $command
|
||||
|
||||
|
||||
# A common mistake is not to use list functions when building up a command
|
||||
set command {set name}
|
||||
append command { Archibald Sorbisol}
|
||||
eval $command ;# There is an error here, because there are too many arguments \
|
||||
to "set" in {set name Archibald Sorbisol}
|
||||
|
||||
|
||||
# This mistake can easily occur with the "subst" command.
|
||||
set replacement {Archibald Sorbisol}
|
||||
set command {set name $replacement}
|
||||
set command [subst $command]
|
||||
eval $command ;# The same error as before: to many arguments to "set" in \
|
||||
{set name Archibald Sorbisol}
|
||||
|
||||
|
||||
# The proper way is to format the substituted value using use the "list"
|
||||
# command.
|
||||
set replacement [list {Archibald Sorbisol}]
|
||||
set command {set name $replacement}
|
||||
set command [subst $command]
|
||||
eval $command
|
||||
|
||||
|
||||
# It is extremely common to see the "list" command being used to properly
|
||||
# format values that are substituted into Tcl script templates. There are
|
||||
# several examples of this, below.
|
||||
|
||||
|
||||
# The "apply" command evaluates a string as a command.
|
||||
set cmd {{greeting name} {
|
||||
return "$greeting, $name!"
|
||||
}}
|
||||
apply $cmd Whaddup Neo
|
||||
|
||||
|
||||
# The "uplevel" command evaluates a script in some enclosing scope.
|
||||
proc greet {} {
|
||||
uplevel {puts "$greeting, $name"}
|
||||
}
|
||||
|
||||
proc set_double {varname value} {
|
||||
if {[string is double $value]} {
|
||||
uplevel [list variable $varname $value]
|
||||
} else {
|
||||
error [list {not a double} $value]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# The "upvar" command links a variable in the current scope to a variable in
|
||||
# some enclosing scope
|
||||
proc set_double {varname value} {
|
||||
if {[string is double $value]} {
|
||||
upvar 1 $varname var
|
||||
set var $value
|
||||
} else {
|
||||
error [list {not a double} $value]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#get rid of the built-in "while" command.
|
||||
rename ::while {}
|
||||
|
||||
|
||||
# Define a new while command with the "proc" command. More sophisticated error
|
||||
# handling is left as an exercise.
|
||||
proc while {condition script} {
|
||||
if {[uplevel 1 [list expr $condition]]} {
|
||||
uplevel 1 $script
|
||||
tailcall [namespace which while] $condition $script
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# The "coroutine" command creates a separate call stack, along with a command
|
||||
# to enter that call stack. The "yield" command suspends execution in that
|
||||
# stack.
|
||||
proc countdown {} {
|
||||
#send something back to the initial "coroutine" command
|
||||
yield
|
||||
|
||||
set count 3
|
||||
while {$count > 1} {
|
||||
yield [incr count -1]
|
||||
}
|
||||
return 0
|
||||
}
|
||||
coroutine countdown1 countdown
|
||||
coroutine countdown2 countdown
|
||||
puts [countdown 1] ;# -> 2
|
||||
puts [countdown 2] ;# -> 2
|
||||
puts [countdown 1] ;# -> 1
|
||||
puts [countdown 1] ;# -> 0
|
||||
puts [coundown 1] ;# -> invalid command name "countdown1"
|
||||
puts [countdown 2] ;# -> 1
|
||||
|
||||
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
[Official Tcl Documentation](http://www.tcl.tk/man/tcl/)
|
||||
|
||||
[Tcl Wiki](http://wiki.tcl.tk)
|
||||
|
||||
[Tcl Subreddit](http://www.reddit.com/r/Tcl)
|
@ -63,8 +63,8 @@ foo = anUnknownVariable -- 现在 foo = nil.
|
||||
|
||||
aBoolValue = false
|
||||
|
||||
--只有nil和false为假; 0和 ''都均为真!
|
||||
if not aBoolValue then print('twas false') end
|
||||
--只有nil和false为假; 0和 ''均为真!
|
||||
if not aBoolValue then print('false') end
|
||||
|
||||
-- 'or'和 'and'短路
|
||||
-- 类似于C/js里的 a?b:c 操作符:
|
||||
@ -149,7 +149,7 @@ print {} -- 一样可以工作。
|
||||
-- Table = Lua唯一的组合数据结构;
|
||||
-- 它们是关联数组。
|
||||
-- 类似于PHP的数组或者js的对象,
|
||||
-- 它们是哈希表或者字典,也可以当初列表使用。
|
||||
-- 它们是哈希表或者字典,也可以当列表使用。
|
||||
|
||||
-- 按字典/map的方式使用Table:
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user