mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2024-12-23 09:41:36 +00:00
Convert \r\n to \n
This commit is contained in:
parent
4ab1be1be5
commit
818b8eec46
@ -1,212 +1,212 @@
|
||||
---
|
||||
category: tool
|
||||
tool: amd
|
||||
contributors:
|
||||
- ["Frederik Ring", "https://github.com/m90"]
|
||||
filename: learnamd.js
|
||||
---
|
||||
|
||||
## Getting Started with AMD
|
||||
|
||||
The **Asynchronous Module Definition** API specifies a mechanism for defining
|
||||
JavaScript modules such that the module and its dependencies can be asynchronously
|
||||
loaded. This is particularly well suited for the browser environment where
|
||||
synchronous loading of modules incurs performance, usability, debugging, and
|
||||
cross-domain access problems.
|
||||
|
||||
### Basic concept
|
||||
```javascript
|
||||
// The basic AMD API consists of nothing but two methods: `define` and `require`
|
||||
// and is all about module definition and consumption:
|
||||
// `define(id?, dependencies?, factory)` defines a module
|
||||
// `require(dependencies, callback)` imports a set of dependencies and
|
||||
// consumes them in the passed callback
|
||||
|
||||
// Let's start by using define to define a new named module
|
||||
// that has no dependencies. We'll do so by passing a name
|
||||
// and a factory function to define:
|
||||
define('awesomeAMD', function(){
|
||||
var isAMDAwesome = function(){
|
||||
return true;
|
||||
};
|
||||
// The return value of a module's factory function is
|
||||
// what other modules or require calls will receive when
|
||||
// requiring our `awesomeAMD` module.
|
||||
// The exported value can be anything, (constructor) functions,
|
||||
// objects, primitives, even undefined (although that won't help too much).
|
||||
return isAMDAwesome;
|
||||
});
|
||||
|
||||
// Now, let's define another module that depends upon our `awesomeAMD` module.
|
||||
// Notice that there's an additional argument defining our
|
||||
// module's dependencies now:
|
||||
define('loudmouth', ['awesomeAMD'], function(awesomeAMD){
|
||||
// dependencies will be passed to the factory's arguments
|
||||
// in the order they are specified
|
||||
var tellEveryone = function(){
|
||||
if (awesomeAMD()){
|
||||
alert('This is sOoOo rad!');
|
||||
} else {
|
||||
alert('Pretty dull, isn\'t it?');
|
||||
}
|
||||
};
|
||||
return tellEveryone;
|
||||
});
|
||||
|
||||
// As we do know how to use define now, let's use `require` to
|
||||
// kick off our program. `require`'s signature is `(arrayOfDependencies, callback)`.
|
||||
require(['loudmouth'], function(loudmouth){
|
||||
loudmouth();
|
||||
});
|
||||
|
||||
// To make this tutorial run code, let's implement a very basic
|
||||
// (non-asynchronous) version of AMD right here on the spot:
|
||||
function define(name, deps, factory){
|
||||
// notice how modules without dependencies are handled
|
||||
define[name] = require(factory ? deps : [], factory || deps);
|
||||
}
|
||||
|
||||
function require(deps, callback){
|
||||
var args = [];
|
||||
// first let's retrieve all the dependencies needed
|
||||
// by the require call
|
||||
for (var i = 0; i < deps.length; i++){
|
||||
args[i] = define[deps[i]];
|
||||
}
|
||||
// satisfy all the callback's dependencies
|
||||
return callback.apply(null, args);
|
||||
}
|
||||
// you can see this code in action here: http://jsfiddle.net/qap949pd/
|
||||
```
|
||||
|
||||
### Real-world usage with require.js
|
||||
|
||||
In contrast to the introductory example, `require.js` (the most popular AMD library) actually implements the **A** in **AMD**, enabling you to load modules and their dependencies asynchronously via XHR:
|
||||
|
||||
```javascript
|
||||
/* file: app/main.js */
|
||||
require(['modules/someClass'], function(SomeClass){
|
||||
// the callback is deferred until the dependency is loaded
|
||||
var thing = new SomeClass();
|
||||
});
|
||||
console.log('So here we are, waiting!'); // this will run first
|
||||
```
|
||||
|
||||
By convention, you usually store one module in one file. `require.js` can resolve module names based on file paths, so you don't have to name your modules, but can simply reference them using their location. In the example `someClass` is assumed to be in the `modules` folder, relative to your configuration's `baseUrl`:
|
||||
|
||||
* app/
|
||||
* main.js
|
||||
* modules/
|
||||
* someClass.js
|
||||
* someHelpers.js
|
||||
* ...
|
||||
* daos/
|
||||
* things.js
|
||||
* ...
|
||||
|
||||
This means we can define `someClass` without specifying a module id:
|
||||
|
||||
```javascript
|
||||
/* file: app/modules/someClass.js */
|
||||
define(['daos/things', 'modules/someHelpers'], function(thingsDao, helpers){
|
||||
// module definition, of course, will also happen asynchronously
|
||||
function SomeClass(){
|
||||
this.method = function(){/**/};
|
||||
// ...
|
||||
}
|
||||
return SomeClass;
|
||||
});
|
||||
```
|
||||
To alter the default path mapping behavior use `requirejs.config(configObj)` in your `main.js`:
|
||||
|
||||
```javascript
|
||||
/* file: main.js */
|
||||
requirejs.config({
|
||||
baseUrl : 'app',
|
||||
paths : {
|
||||
// you can also load modules from other locations
|
||||
jquery : '//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min',
|
||||
coolLibFromBower : '../bower_components/cool-lib/coollib'
|
||||
}
|
||||
});
|
||||
require(['jquery', 'coolLibFromBower', 'modules/someHelpers'], function($, coolLib, helpers){
|
||||
// a `main` file needs to call require at least once,
|
||||
// otherwise no code will ever run
|
||||
coolLib.doFancyStuffWith(helpers.transform($('#foo')));
|
||||
});
|
||||
```
|
||||
`require.js`-based apps will usually have a single entry point (`main.js`) that is passed to the `require.js` script tag as a data-attribute. It will be automatically loaded and executed on pageload:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>A hundred script tags? Never again!</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="require.js" data-main="app/main"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
### Optimizing a whole project using r.js
|
||||
|
||||
Many people prefer using AMD for sane code organization during development, but still want to ship a single script file in production instead of performing hundreds of XHRs on page load.
|
||||
|
||||
`require.js` comes with a script called `r.js` (that you will probably run in node.js, although Rhino is supported too) that can analyse your project's dependency graph, and build a single file containing all your modules (properly named), minified and ready for consumption.
|
||||
|
||||
Install it using `npm`:
|
||||
```shell
|
||||
$ npm install requirejs -g
|
||||
```
|
||||
|
||||
Now you can feed it with a configuration file:
|
||||
```shell
|
||||
$ r.js -o app.build.js
|
||||
```
|
||||
|
||||
For our above example the configuration might look like:
|
||||
```javascript
|
||||
/* file : app.build.js */
|
||||
({
|
||||
name : 'main', // name of the entry point
|
||||
out : 'main-built.js', // name of the file to write the output to
|
||||
baseUrl : 'app',
|
||||
paths : {
|
||||
// `empty:` tells r.js that this should still be loaded from the CDN, using
|
||||
// the location specified in `main.js`
|
||||
jquery : 'empty:',
|
||||
coolLibFromBower : '../bower_components/cool-lib/coollib'
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
To use the built file in production, simply swap `data-main`:
|
||||
```html
|
||||
<script src="require.js" data-main="app/main-built"></script>
|
||||
```
|
||||
|
||||
An incredibly detailed [overview of build options](https://github.com/jrburke/r.js/blob/master/build/example.build.js) is available in the GitHub repo.
|
||||
|
||||
### Topics not covered in this tutorial
|
||||
* [Loader plugins / transforms](http://requirejs.org/docs/plugins.html)
|
||||
* [CommonJS style loading and exporting](http://requirejs.org/docs/commonjs.html)
|
||||
* [Advanced configuration](http://requirejs.org/docs/api.html#config)
|
||||
* [Shim configuration (loading non-AMD modules)](http://requirejs.org/docs/api.html#config-shim)
|
||||
* [CSS loading and optimizing with require.js](http://requirejs.org/docs/optimization.html#onecss)
|
||||
* [Using almond.js for builds](https://github.com/jrburke/almond)
|
||||
|
||||
### Further reading:
|
||||
|
||||
* [Official Spec](https://github.com/amdjs/amdjs-api/wiki/AMD)
|
||||
* [Why AMD?](http://requirejs.org/docs/whyamd.html)
|
||||
* [Universal Module Definition](https://github.com/umdjs/umd)
|
||||
|
||||
### Implementations:
|
||||
|
||||
* [require.js](http://requirejs.org)
|
||||
* [dojo toolkit](http://dojotoolkit.org/documentation/tutorials/1.9/modules/)
|
||||
* [cujo.js](http://cujojs.com/)
|
||||
* [curl.js](https://github.com/cujojs/curl)
|
||||
* [lsjs](https://github.com/zazl/lsjs)
|
||||
* [mmd](https://github.com/alexlawrence/mmd)
|
||||
---
|
||||
category: tool
|
||||
tool: amd
|
||||
contributors:
|
||||
- ["Frederik Ring", "https://github.com/m90"]
|
||||
filename: learnamd.js
|
||||
---
|
||||
|
||||
## Getting Started with AMD
|
||||
|
||||
The **Asynchronous Module Definition** API specifies a mechanism for defining
|
||||
JavaScript modules such that the module and its dependencies can be asynchronously
|
||||
loaded. This is particularly well suited for the browser environment where
|
||||
synchronous loading of modules incurs performance, usability, debugging, and
|
||||
cross-domain access problems.
|
||||
|
||||
### Basic concept
|
||||
```javascript
|
||||
// The basic AMD API consists of nothing but two methods: `define` and `require`
|
||||
// and is all about module definition and consumption:
|
||||
// `define(id?, dependencies?, factory)` defines a module
|
||||
// `require(dependencies, callback)` imports a set of dependencies and
|
||||
// consumes them in the passed callback
|
||||
|
||||
// Let's start by using define to define a new named module
|
||||
// that has no dependencies. We'll do so by passing a name
|
||||
// and a factory function to define:
|
||||
define('awesomeAMD', function(){
|
||||
var isAMDAwesome = function(){
|
||||
return true;
|
||||
};
|
||||
// The return value of a module's factory function is
|
||||
// what other modules or require calls will receive when
|
||||
// requiring our `awesomeAMD` module.
|
||||
// The exported value can be anything, (constructor) functions,
|
||||
// objects, primitives, even undefined (although that won't help too much).
|
||||
return isAMDAwesome;
|
||||
});
|
||||
|
||||
// Now, let's define another module that depends upon our `awesomeAMD` module.
|
||||
// Notice that there's an additional argument defining our
|
||||
// module's dependencies now:
|
||||
define('loudmouth', ['awesomeAMD'], function(awesomeAMD){
|
||||
// dependencies will be passed to the factory's arguments
|
||||
// in the order they are specified
|
||||
var tellEveryone = function(){
|
||||
if (awesomeAMD()){
|
||||
alert('This is sOoOo rad!');
|
||||
} else {
|
||||
alert('Pretty dull, isn\'t it?');
|
||||
}
|
||||
};
|
||||
return tellEveryone;
|
||||
});
|
||||
|
||||
// As we do know how to use define now, let's use `require` to
|
||||
// kick off our program. `require`'s signature is `(arrayOfDependencies, callback)`.
|
||||
require(['loudmouth'], function(loudmouth){
|
||||
loudmouth();
|
||||
});
|
||||
|
||||
// To make this tutorial run code, let's implement a very basic
|
||||
// (non-asynchronous) version of AMD right here on the spot:
|
||||
function define(name, deps, factory){
|
||||
// notice how modules without dependencies are handled
|
||||
define[name] = require(factory ? deps : [], factory || deps);
|
||||
}
|
||||
|
||||
function require(deps, callback){
|
||||
var args = [];
|
||||
// first let's retrieve all the dependencies needed
|
||||
// by the require call
|
||||
for (var i = 0; i < deps.length; i++){
|
||||
args[i] = define[deps[i]];
|
||||
}
|
||||
// satisfy all the callback's dependencies
|
||||
return callback.apply(null, args);
|
||||
}
|
||||
// you can see this code in action here: http://jsfiddle.net/qap949pd/
|
||||
```
|
||||
|
||||
### Real-world usage with require.js
|
||||
|
||||
In contrast to the introductory example, `require.js` (the most popular AMD library) actually implements the **A** in **AMD**, enabling you to load modules and their dependencies asynchronously via XHR:
|
||||
|
||||
```javascript
|
||||
/* file: app/main.js */
|
||||
require(['modules/someClass'], function(SomeClass){
|
||||
// the callback is deferred until the dependency is loaded
|
||||
var thing = new SomeClass();
|
||||
});
|
||||
console.log('So here we are, waiting!'); // this will run first
|
||||
```
|
||||
|
||||
By convention, you usually store one module in one file. `require.js` can resolve module names based on file paths, so you don't have to name your modules, but can simply reference them using their location. In the example `someClass` is assumed to be in the `modules` folder, relative to your configuration's `baseUrl`:
|
||||
|
||||
* app/
|
||||
* main.js
|
||||
* modules/
|
||||
* someClass.js
|
||||
* someHelpers.js
|
||||
* ...
|
||||
* daos/
|
||||
* things.js
|
||||
* ...
|
||||
|
||||
This means we can define `someClass` without specifying a module id:
|
||||
|
||||
```javascript
|
||||
/* file: app/modules/someClass.js */
|
||||
define(['daos/things', 'modules/someHelpers'], function(thingsDao, helpers){
|
||||
// module definition, of course, will also happen asynchronously
|
||||
function SomeClass(){
|
||||
this.method = function(){/**/};
|
||||
// ...
|
||||
}
|
||||
return SomeClass;
|
||||
});
|
||||
```
|
||||
To alter the default path mapping behavior use `requirejs.config(configObj)` in your `main.js`:
|
||||
|
||||
```javascript
|
||||
/* file: main.js */
|
||||
requirejs.config({
|
||||
baseUrl : 'app',
|
||||
paths : {
|
||||
// you can also load modules from other locations
|
||||
jquery : '//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min',
|
||||
coolLibFromBower : '../bower_components/cool-lib/coollib'
|
||||
}
|
||||
});
|
||||
require(['jquery', 'coolLibFromBower', 'modules/someHelpers'], function($, coolLib, helpers){
|
||||
// a `main` file needs to call require at least once,
|
||||
// otherwise no code will ever run
|
||||
coolLib.doFancyStuffWith(helpers.transform($('#foo')));
|
||||
});
|
||||
```
|
||||
`require.js`-based apps will usually have a single entry point (`main.js`) that is passed to the `require.js` script tag as a data-attribute. It will be automatically loaded and executed on pageload:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>A hundred script tags? Never again!</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="require.js" data-main="app/main"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
### Optimizing a whole project using r.js
|
||||
|
||||
Many people prefer using AMD for sane code organization during development, but still want to ship a single script file in production instead of performing hundreds of XHRs on page load.
|
||||
|
||||
`require.js` comes with a script called `r.js` (that you will probably run in node.js, although Rhino is supported too) that can analyse your project's dependency graph, and build a single file containing all your modules (properly named), minified and ready for consumption.
|
||||
|
||||
Install it using `npm`:
|
||||
```shell
|
||||
$ npm install requirejs -g
|
||||
```
|
||||
|
||||
Now you can feed it with a configuration file:
|
||||
```shell
|
||||
$ r.js -o app.build.js
|
||||
```
|
||||
|
||||
For our above example the configuration might look like:
|
||||
```javascript
|
||||
/* file : app.build.js */
|
||||
({
|
||||
name : 'main', // name of the entry point
|
||||
out : 'main-built.js', // name of the file to write the output to
|
||||
baseUrl : 'app',
|
||||
paths : {
|
||||
// `empty:` tells r.js that this should still be loaded from the CDN, using
|
||||
// the location specified in `main.js`
|
||||
jquery : 'empty:',
|
||||
coolLibFromBower : '../bower_components/cool-lib/coollib'
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
To use the built file in production, simply swap `data-main`:
|
||||
```html
|
||||
<script src="require.js" data-main="app/main-built"></script>
|
||||
```
|
||||
|
||||
An incredibly detailed [overview of build options](https://github.com/jrburke/r.js/blob/master/build/example.build.js) is available in the GitHub repo.
|
||||
|
||||
### Topics not covered in this tutorial
|
||||
* [Loader plugins / transforms](http://requirejs.org/docs/plugins.html)
|
||||
* [CommonJS style loading and exporting](http://requirejs.org/docs/commonjs.html)
|
||||
* [Advanced configuration](http://requirejs.org/docs/api.html#config)
|
||||
* [Shim configuration (loading non-AMD modules)](http://requirejs.org/docs/api.html#config-shim)
|
||||
* [CSS loading and optimizing with require.js](http://requirejs.org/docs/optimization.html#onecss)
|
||||
* [Using almond.js for builds](https://github.com/jrburke/almond)
|
||||
|
||||
### Further reading:
|
||||
|
||||
* [Official Spec](https://github.com/amdjs/amdjs-api/wiki/AMD)
|
||||
* [Why AMD?](http://requirejs.org/docs/whyamd.html)
|
||||
* [Universal Module Definition](https://github.com/umdjs/umd)
|
||||
|
||||
### Implementations:
|
||||
|
||||
* [require.js](http://requirejs.org)
|
||||
* [dojo toolkit](http://dojotoolkit.org/documentation/tutorials/1.9/modules/)
|
||||
* [cujo.js](http://cujojs.com/)
|
||||
* [curl.js](https://github.com/cujojs/curl)
|
||||
* [lsjs](https://github.com/zazl/lsjs)
|
||||
* [mmd](https://github.com/alexlawrence/mmd)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,423 +1,423 @@
|
||||
---
|
||||
language: Elixir
|
||||
contributors:
|
||||
- ["Joao Marques", "http://github.com/mrshankly"]
|
||||
translators:
|
||||
- ["Gregor Große-Bölting", "http://www.ideen-und-soehne.de"]
|
||||
filename: learnelixir-de.ex
|
||||
lang: de-de
|
||||
---
|
||||
|
||||
Elixir ist eine moderne, funktionale Sprache für die Erlang VM. Sie ist voll
|
||||
kompatibel mit Erlang, verfügt aber über eine freundlichere Syntax und bringt
|
||||
viele Features mit.
|
||||
|
||||
```ruby
|
||||
|
||||
# Einzeilige Kommentare werden mit der Raute gesetzt.
|
||||
|
||||
# Es gibt keine mehrzeiligen Kommentare;
|
||||
# es ist aber problemlos möglich mehrere einzeilige Kommentare hintereinander
|
||||
# zu setzen (so wie hier).
|
||||
|
||||
# Mit 'iex' ruft man die Elixir-Shell auf.
|
||||
# Zum kompilieren von Modulen dient der Befehl 'elixirc'.
|
||||
|
||||
# Beide Befehle sollten als Umgebungsvariable gesetzt sein, wenn Elixir korrekt
|
||||
# installiert wurde.
|
||||
|
||||
## ---------------------------
|
||||
## -- Basistypen
|
||||
## ---------------------------
|
||||
|
||||
# Es gibt Nummern:
|
||||
3 # Integer
|
||||
0x1F # Integer
|
||||
3.0 # Float
|
||||
|
||||
# Für bessere Lesbarkeit des Codes können Unterstriche "_" als Trennzeichen verwendet werden
|
||||
1_000_000 == 1000000 # Integer
|
||||
1_000.567 == 1000.567 # Float
|
||||
|
||||
# Atome, das sind Literale, sind Konstanten mit Namen. Sie starten mit einem
|
||||
# ':'.
|
||||
:hello # Atom
|
||||
|
||||
# Außerdem gibt es Tupel, deren Werte im Arbeitsspeicher vorgehalten werden.
|
||||
{1,2,3} # Tupel
|
||||
|
||||
# Die Werte innerhalb eines Tupels können mit der 'elem'-Funktion ausgelesen
|
||||
# werden:
|
||||
elem({1, 2, 3}, 0) # => 1
|
||||
|
||||
# Listen sind als verkettete Listen implementiert.
|
||||
[1, 2, 3] # list
|
||||
|
||||
# Auf Kopf und Rest einer Liste kann wie folgt zugegriffen werden:
|
||||
[ kopf | rest ] = [1,2,3]
|
||||
kopf # => 1
|
||||
rest # => [2, 3]
|
||||
|
||||
# In Elixir, wie auch in Erlang, kennzeichnet '=' ein 'pattern matching'
|
||||
# (Musterabgleich) und keine Zuweisung.
|
||||
# Das heißt, dass die linke Seite auf die rechte Seite 'abgeglichen' wird.
|
||||
# Auf diese Weise kann im Beispiel oben auf Kopf und Rest der Liste zugegriffen
|
||||
# werden.
|
||||
|
||||
# Ein Musterabgleich wird einen Fehler werfen, wenn die beiden Seiten nicht
|
||||
# zusammenpassen.
|
||||
# Im folgenden Beispiel haben die Tupel eine unterschiedliche Anzahl an
|
||||
# Elementen:
|
||||
{a, b, c} = {1, 2} #=> ** (MatchError) no match of right hand side value: {1,2}
|
||||
|
||||
# Es gibt außerdem 'binaries',
|
||||
<<1,2,3>> # binary.
|
||||
|
||||
# Strings und 'char lists'
|
||||
"hello" # String
|
||||
'hello' # Char-Liste
|
||||
|
||||
# ... und mehrzeilige Strings
|
||||
"""
|
||||
Ich bin ein
|
||||
mehrzeiliger String.
|
||||
"""
|
||||
#=> "Ich bin ein\nmehrzeiliger String.\n"
|
||||
|
||||
# Alles Strings werden in UTF-8 enkodiert:
|
||||
"héllò" #=> "héllò"
|
||||
|
||||
# Eigentlich sind Strings in Wahrheit nur binaries und 'char lists' einfach
|
||||
# Listen.
|
||||
<<?a, ?b, ?c>> #=> "abc"
|
||||
[?a, ?b, ?c] #=> 'abc'
|
||||
|
||||
# In Elixir gibt `?a` den ASCII-Integer für den Buchstaben zurück.
|
||||
?a #=> 97
|
||||
|
||||
# Um Listen zu verbinden gibt es den Operator '++', für binaries nutzt man '<>'
|
||||
[1,2,3] ++ [4,5] #=> [1,2,3,4,5]
|
||||
'hello ' ++ 'world' #=> 'hello world'
|
||||
|
||||
<<1,2,3>> <> <<4,5>> #=> <<1,2,3,4,5>>
|
||||
"hello " <> "world" #=> "hello world"
|
||||
|
||||
## ---------------------------
|
||||
## -- Operatoren
|
||||
## ---------------------------
|
||||
|
||||
# Einfache Arithmetik
|
||||
1 + 1 #=> 2
|
||||
10 - 5 #=> 5
|
||||
5 * 2 #=> 10
|
||||
10 / 2 #=> 5.0
|
||||
|
||||
# In Elixir gibt der Operator '/' immer einen Float-Wert zurück.
|
||||
|
||||
# Für Division mit ganzzahligen Ergebnis gibt es 'div'
|
||||
div(10, 2) #=> 5
|
||||
|
||||
# Um den Rest der ganzzahligen Division zu erhalten gibt es 'rem'
|
||||
rem(10, 3) #=> 1
|
||||
|
||||
# Natürlich gibt es auch Operatoren für Booleans: 'or', 'and' und 'not'. Diese
|
||||
# Operatoren erwarten einen Boolean als erstes Argument.
|
||||
true and true #=> true
|
||||
false or true #=> true
|
||||
# 1 and true #=> ** (ArgumentError) argument error
|
||||
|
||||
# Elixir bietet auch '||', '&&' und '!', die Argumente jedweden Typs
|
||||
# akzeptieren. Alle Werte außer 'false' und 'nil' werden zu wahr evaluiert.
|
||||
1 || true #=> 1
|
||||
false && 1 #=> false
|
||||
nil && 20 #=> nil
|
||||
|
||||
!true #=> false
|
||||
|
||||
# Für Vergleiche gibt es die Operatoren `==`, `!=`, `===`, `!==`, `<=`, `>=`,
|
||||
# `<` und `>`
|
||||
1 == 1 #=> true
|
||||
1 != 1 #=> false
|
||||
1 < 2 #=> true
|
||||
|
||||
# '===' und '!==' sind strikter beim Vergleich von Integern und Floats:
|
||||
1 == 1.0 #=> true
|
||||
1 === 1.0 #=> false
|
||||
|
||||
# Es ist außerdem möglich zwei verschiedene Datentypen zu vergleichen:
|
||||
1 < :hello #=> true
|
||||
|
||||
# Die gesamte Ordnung über die Datentypen ist wie folgt definiert:
|
||||
# number < atom < reference < functions < port < pid < tuple < list < bitstring
|
||||
|
||||
# Um Joe Armstrong zu zitieren: "The actual order is not important, but that a
|
||||
# total ordering is well defined is important."
|
||||
|
||||
## ---------------------------
|
||||
## -- Kontrollstrukturen
|
||||
## ---------------------------
|
||||
|
||||
# Es gibt die `if`-Verzweigung
|
||||
if false do
|
||||
"Dies wird nie jemand sehen..."
|
||||
else
|
||||
"...aber dies!"
|
||||
end
|
||||
|
||||
# ...und ebenso `unless`
|
||||
unless true do
|
||||
"Dies wird nie jemand sehen..."
|
||||
else
|
||||
"...aber dies!"
|
||||
end
|
||||
|
||||
# Du erinnerst dich an 'pattern matching'? Viele Kontrollstrukturen in Elixir
|
||||
# arbeiten damit.
|
||||
|
||||
# 'case' erlaubt es uns Werte mit vielerlei Mustern zu vergleichen.
|
||||
case {:one, :two} do
|
||||
{:four, :five} ->
|
||||
"Das wird nicht passen"
|
||||
{:one, x} ->
|
||||
"Das schon und außerdem wird es ':two' dem Wert 'x' zuweisen."
|
||||
_ ->
|
||||
"Dieser Fall greift immer."
|
||||
end
|
||||
|
||||
# Es ist eine übliche Praxis '_' einen Wert zuzuweisen, sofern dieser Wert
|
||||
# nicht weiter verwendet wird.
|
||||
# Wenn wir uns zum Beispiel nur für den Kopf einer Liste interessieren:
|
||||
[kopf | _] = [1,2,3]
|
||||
kopf #=> 1
|
||||
|
||||
# Für bessere Lesbarkeit können wir auch das Folgende machen:
|
||||
[kopf | _rest] = [:a, :b, :c]
|
||||
kopf #=> :a
|
||||
|
||||
# Mit 'cond' können diverse Bedingungen zur selben Zeit überprüft werden. Man
|
||||
# benutzt 'cond' statt viele if-Verzweigungen zu verschachteln.
|
||||
cond do
|
||||
1 + 1 == 3 ->
|
||||
"Ich werde nie aufgerufen."
|
||||
2 * 5 == 12 ->
|
||||
"Ich auch nicht."
|
||||
1 + 2 == 3 ->
|
||||
"Aber ich!"
|
||||
end
|
||||
|
||||
# Es ist üblich eine letzte Bedingung einzufügen, die immer zu wahr evaluiert.
|
||||
cond do
|
||||
1 + 1 == 3 ->
|
||||
"Ich werde nie aufgerufen."
|
||||
2 * 5 == 12 ->
|
||||
"Ich auch nicht."
|
||||
true ->
|
||||
"Aber ich! (dies ist im Grunde ein 'else')"
|
||||
end
|
||||
|
||||
# 'try/catch' wird verwendet um Werte zu fangen, die zuvor 'geworfen' wurden.
|
||||
# Das Konstrukt unterstützt außerdem eine 'after'-Klausel die aufgerufen wird,
|
||||
# egal ob zuvor ein Wert gefangen wurde.
|
||||
try do
|
||||
throw(:hello)
|
||||
catch
|
||||
nachricht -> "#{nachricht} gefangen."
|
||||
after
|
||||
IO.puts("Ich bin die 'after'-Klausel.")
|
||||
end
|
||||
#=> Ich bin die 'after'-Klausel.
|
||||
# ":hello gefangen"
|
||||
|
||||
## ---------------------------
|
||||
## -- Module und Funktionen
|
||||
## ---------------------------
|
||||
|
||||
# Anonyme Funktionen (man beachte den Punkt)
|
||||
square = fn(x) -> x * x end
|
||||
square.(5) #=> 25
|
||||
|
||||
# Anonyme Funktionen unterstützen auch 'pattern' und 'guards'. Guards erlauben
|
||||
# es die Mustererkennung zu justieren und werden mit dem Schlüsselwort 'when'
|
||||
# eingeführt:
|
||||
f = fn
|
||||
x, y when x > 0 -> x + y
|
||||
x, y -> x * y
|
||||
end
|
||||
|
||||
f.(1, 3) #=> 4
|
||||
f.(-1, 3) #=> -3
|
||||
|
||||
# Elixir bietet zahlreiche eingebaute Funktionen. Diese sind im gleichen
|
||||
# Geltungsbereich ('scope') verfügbar.
|
||||
is_number(10) #=> true
|
||||
is_list("hello") #=> false
|
||||
elem({1,2,3}, 0) #=> 1
|
||||
|
||||
# Mehrere Funktionen können in einem Modul gruppiert werden. Innerhalb eines
|
||||
# Moduls ist es möglich mit dem Schlüsselwort 'def' eine Funktion zu
|
||||
# definieren.
|
||||
defmodule Math do
|
||||
def sum(a, b) do
|
||||
a + b
|
||||
end
|
||||
|
||||
def square(x) do
|
||||
x * x
|
||||
end
|
||||
end
|
||||
|
||||
Math.sum(1, 2) #=> 3
|
||||
Math.square(3) #=> 9
|
||||
|
||||
# Um unser einfaches Mathe-Modul zu kompilieren muss es unter 'math.ex'
|
||||
# gesichert werden. Anschließend kann es mit 'elixirc' im Terminal aufgerufen
|
||||
# werden: elixirc math.ex
|
||||
|
||||
# Innerhalb eines Moduls definieren wir private Funktionen mit 'defp'. Eine
|
||||
# Funktion, die mit 'def' erstellt wurde, kann von anderen Modulen aufgerufen
|
||||
# werden; eine private Funktion kann nur lokal angesprochen werden.
|
||||
defmodule PrivateMath do
|
||||
def sum(a, b) do
|
||||
do_sum(a, b)
|
||||
end
|
||||
|
||||
defp do_sum(a, b) do
|
||||
a + b
|
||||
end
|
||||
end
|
||||
|
||||
PrivateMath.sum(1, 2) #=> 3
|
||||
# PrivateMath.do_sum(1, 2) #=> ** (UndefinedFunctionError)
|
||||
|
||||
# Auch Funktionsdeklarationen unterstützen 'guards' und Mustererkennung:
|
||||
defmodule Geometry do
|
||||
def area({:rectangle, w, h}) do
|
||||
w * h
|
||||
end
|
||||
|
||||
def area({:circle, r}) when is_number(r) do
|
||||
3.14 * r * r
|
||||
end
|
||||
end
|
||||
|
||||
Geometry.area({:rectangle, 2, 3}) #=> 6
|
||||
Geometry.area({:circle, 3}) #=> 28.25999999999999801048
|
||||
# Geometry.area({:circle, "not_a_number"})
|
||||
#=> ** (FunctionClauseError) no function clause matching in Geometry.area/1
|
||||
|
||||
# Wegen der Unveränderlichkeit von Variablen ist Rekursion ein wichtiger
|
||||
# Bestandteil von Elixir.
|
||||
defmodule Recursion do
|
||||
def sum_list([head | tail], acc) do
|
||||
sum_list(tail, acc + head)
|
||||
end
|
||||
|
||||
def sum_list([], acc) do
|
||||
acc
|
||||
end
|
||||
end
|
||||
|
||||
Recursion.sum_list([1,2,3], 0) #=> 6
|
||||
|
||||
# Elixir-Module unterstützen Attribute. Es gibt eingebaute Attribute, ebenso
|
||||
# ist es möglich eigene Attribute hinzuzufügen.
|
||||
defmodule MyMod do
|
||||
@moduledoc """
|
||||
Dies ist ein eingebautes Attribut in einem Beispiel-Modul
|
||||
"""
|
||||
|
||||
@my_data 100 # Dies ist ein selbst-definiertes Attribut.
|
||||
IO.inspect(@my_data) #=> 100
|
||||
end
|
||||
|
||||
## ---------------------------
|
||||
## -- 'Records' und Ausnahmebehandlung
|
||||
## ---------------------------
|
||||
|
||||
# 'Records' sind im Grunde Strukturen, die es erlauben einem Wert einen eigenen
|
||||
# Namen zuzuweisen.
|
||||
defrecord Person, name: nil, age: 0, height: 0
|
||||
|
||||
joe_info = Person.new(name: "Joe", age: 30, height: 180)
|
||||
#=> Person[name: "Joe", age: 30, height: 180]
|
||||
|
||||
# Zugriff auf den Wert von 'name'
|
||||
joe_info.name #=> "Joe"
|
||||
|
||||
# Den Wert von 'age' überschreiben
|
||||
joe_info = joe_info.age(31) #=> Person[name: "Joe", age: 31, height: 180]
|
||||
|
||||
# Der 'try'-Block wird zusammen mit dem 'rescue'-Schlüsselwort dazu verwendet,
|
||||
# um Ausnahmen beziehungsweise Fehler zu behandeln.
|
||||
try do
|
||||
raise "Irgendein Fehler."
|
||||
rescue
|
||||
RuntimeError -> "Laufzeit-Fehler gefangen."
|
||||
_error -> "Und dies fängt jeden Fehler."
|
||||
end
|
||||
|
||||
# Alle Ausnahmen haben das Attribut 'message'
|
||||
try do
|
||||
raise "ein Fehler"
|
||||
rescue
|
||||
x in [RuntimeError] ->
|
||||
x.message
|
||||
end
|
||||
|
||||
## ---------------------------
|
||||
## -- Nebenläufigkeit
|
||||
## ---------------------------
|
||||
|
||||
# Elixir beruht auf dem Aktoren-Model zur Behandlung der Nebenläufigkeit. Alles
|
||||
# was man braucht um in Elixir nebenläufige Programme zu schreiben sind drei
|
||||
# Primitive: Prozesse erzeugen, Nachrichten senden und Nachrichten empfangen.
|
||||
|
||||
# Um einen neuen Prozess zu erzeugen nutzen wir die 'spawn'-Funktion, die
|
||||
# wiederum eine Funktion als Argument entgegen nimmt.
|
||||
f = fn -> 2 * 2 end #=> #Function<erl_eval.20.80484245>
|
||||
spawn(f) #=> #PID<0.40.0>
|
||||
|
||||
# 'spawn' gibt eine pid (einen Identifikator des Prozesses) zurück. Diese kann
|
||||
# nun verwendet werden, um Nachrichten an den Prozess zu senden. Um
|
||||
# zu senden nutzen wir den '<-' Operator. Damit das alles Sinn macht müssen wir
|
||||
# in der Lage sein Nachrichten zu empfangen. Dies wird mit dem
|
||||
# 'receive'-Mechanismus sichergestellt:
|
||||
defmodule Geometry do
|
||||
def area_loop do
|
||||
receive do
|
||||
{:rectangle, w, h} ->
|
||||
IO.puts("Area = #{w * h}")
|
||||
area_loop()
|
||||
{:circle, r} ->
|
||||
IO.puts("Area = #{3.14 * r * r}")
|
||||
area_loop()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Kompiliere das Modul, starte einen Prozess und gib die 'area_loop' Funktion
|
||||
# in der Shell mit, etwa so:
|
||||
pid = spawn(fn -> Geometry.area_loop() end) #=> #PID<0.40.0>
|
||||
|
||||
# Sende eine Nachricht an die 'pid', die ein Muster im 'receive'-Ausdruck
|
||||
# erfüllt:
|
||||
pid <- {:rectangle, 2, 3}
|
||||
#=> Area = 6
|
||||
# {:rectangle,2,3}
|
||||
|
||||
pid <- {:circle, 2}
|
||||
#=> Area = 12.56000000000000049738
|
||||
# {:circle,2}
|
||||
|
||||
# Die Shell selbst ist ein Prozess und mit dem Schlüsselwort 'self' kann man
|
||||
# die aktuelle pid herausfinden.
|
||||
self() #=> #PID<0.27.0>
|
||||
|
||||
```
|
||||
|
||||
## Referenzen und weitere Lektüre
|
||||
|
||||
* [Getting started guide](http://elixir-lang.org/getting_started/1.html) auf der [elixir Website](http://elixir-lang.org)
|
||||
* [Elixir Documentation](http://elixir-lang.org/docs/master/)
|
||||
* ["Learn You Some Erlang for Great Good!"](http://learnyousomeerlang.com/) von Fred Hebert
|
||||
* "Programming Erlang: Software for a Concurrent World" von Joe Armstrong
|
||||
---
|
||||
language: Elixir
|
||||
contributors:
|
||||
- ["Joao Marques", "http://github.com/mrshankly"]
|
||||
translators:
|
||||
- ["Gregor Große-Bölting", "http://www.ideen-und-soehne.de"]
|
||||
filename: learnelixir-de.ex
|
||||
lang: de-de
|
||||
---
|
||||
|
||||
Elixir ist eine moderne, funktionale Sprache für die Erlang VM. Sie ist voll
|
||||
kompatibel mit Erlang, verfügt aber über eine freundlichere Syntax und bringt
|
||||
viele Features mit.
|
||||
|
||||
```ruby
|
||||
|
||||
# Einzeilige Kommentare werden mit der Raute gesetzt.
|
||||
|
||||
# Es gibt keine mehrzeiligen Kommentare;
|
||||
# es ist aber problemlos möglich mehrere einzeilige Kommentare hintereinander
|
||||
# zu setzen (so wie hier).
|
||||
|
||||
# Mit 'iex' ruft man die Elixir-Shell auf.
|
||||
# Zum kompilieren von Modulen dient der Befehl 'elixirc'.
|
||||
|
||||
# Beide Befehle sollten als Umgebungsvariable gesetzt sein, wenn Elixir korrekt
|
||||
# installiert wurde.
|
||||
|
||||
## ---------------------------
|
||||
## -- Basistypen
|
||||
## ---------------------------
|
||||
|
||||
# Es gibt Nummern:
|
||||
3 # Integer
|
||||
0x1F # Integer
|
||||
3.0 # Float
|
||||
|
||||
# Für bessere Lesbarkeit des Codes können Unterstriche "_" als Trennzeichen verwendet werden
|
||||
1_000_000 == 1000000 # Integer
|
||||
1_000.567 == 1000.567 # Float
|
||||
|
||||
# Atome, das sind Literale, sind Konstanten mit Namen. Sie starten mit einem
|
||||
# ':'.
|
||||
:hello # Atom
|
||||
|
||||
# Außerdem gibt es Tupel, deren Werte im Arbeitsspeicher vorgehalten werden.
|
||||
{1,2,3} # Tupel
|
||||
|
||||
# Die Werte innerhalb eines Tupels können mit der 'elem'-Funktion ausgelesen
|
||||
# werden:
|
||||
elem({1, 2, 3}, 0) # => 1
|
||||
|
||||
# Listen sind als verkettete Listen implementiert.
|
||||
[1, 2, 3] # list
|
||||
|
||||
# Auf Kopf und Rest einer Liste kann wie folgt zugegriffen werden:
|
||||
[ kopf | rest ] = [1,2,3]
|
||||
kopf # => 1
|
||||
rest # => [2, 3]
|
||||
|
||||
# In Elixir, wie auch in Erlang, kennzeichnet '=' ein 'pattern matching'
|
||||
# (Musterabgleich) und keine Zuweisung.
|
||||
# Das heißt, dass die linke Seite auf die rechte Seite 'abgeglichen' wird.
|
||||
# Auf diese Weise kann im Beispiel oben auf Kopf und Rest der Liste zugegriffen
|
||||
# werden.
|
||||
|
||||
# Ein Musterabgleich wird einen Fehler werfen, wenn die beiden Seiten nicht
|
||||
# zusammenpassen.
|
||||
# Im folgenden Beispiel haben die Tupel eine unterschiedliche Anzahl an
|
||||
# Elementen:
|
||||
{a, b, c} = {1, 2} #=> ** (MatchError) no match of right hand side value: {1,2}
|
||||
|
||||
# Es gibt außerdem 'binaries',
|
||||
<<1,2,3>> # binary.
|
||||
|
||||
# Strings und 'char lists'
|
||||
"hello" # String
|
||||
'hello' # Char-Liste
|
||||
|
||||
# ... und mehrzeilige Strings
|
||||
"""
|
||||
Ich bin ein
|
||||
mehrzeiliger String.
|
||||
"""
|
||||
#=> "Ich bin ein\nmehrzeiliger String.\n"
|
||||
|
||||
# Alles Strings werden in UTF-8 enkodiert:
|
||||
"héllò" #=> "héllò"
|
||||
|
||||
# Eigentlich sind Strings in Wahrheit nur binaries und 'char lists' einfach
|
||||
# Listen.
|
||||
<<?a, ?b, ?c>> #=> "abc"
|
||||
[?a, ?b, ?c] #=> 'abc'
|
||||
|
||||
# In Elixir gibt `?a` den ASCII-Integer für den Buchstaben zurück.
|
||||
?a #=> 97
|
||||
|
||||
# Um Listen zu verbinden gibt es den Operator '++', für binaries nutzt man '<>'
|
||||
[1,2,3] ++ [4,5] #=> [1,2,3,4,5]
|
||||
'hello ' ++ 'world' #=> 'hello world'
|
||||
|
||||
<<1,2,3>> <> <<4,5>> #=> <<1,2,3,4,5>>
|
||||
"hello " <> "world" #=> "hello world"
|
||||
|
||||
## ---------------------------
|
||||
## -- Operatoren
|
||||
## ---------------------------
|
||||
|
||||
# Einfache Arithmetik
|
||||
1 + 1 #=> 2
|
||||
10 - 5 #=> 5
|
||||
5 * 2 #=> 10
|
||||
10 / 2 #=> 5.0
|
||||
|
||||
# In Elixir gibt der Operator '/' immer einen Float-Wert zurück.
|
||||
|
||||
# Für Division mit ganzzahligen Ergebnis gibt es 'div'
|
||||
div(10, 2) #=> 5
|
||||
|
||||
# Um den Rest der ganzzahligen Division zu erhalten gibt es 'rem'
|
||||
rem(10, 3) #=> 1
|
||||
|
||||
# Natürlich gibt es auch Operatoren für Booleans: 'or', 'and' und 'not'. Diese
|
||||
# Operatoren erwarten einen Boolean als erstes Argument.
|
||||
true and true #=> true
|
||||
false or true #=> true
|
||||
# 1 and true #=> ** (ArgumentError) argument error
|
||||
|
||||
# Elixir bietet auch '||', '&&' und '!', die Argumente jedweden Typs
|
||||
# akzeptieren. Alle Werte außer 'false' und 'nil' werden zu wahr evaluiert.
|
||||
1 || true #=> 1
|
||||
false && 1 #=> false
|
||||
nil && 20 #=> nil
|
||||
|
||||
!true #=> false
|
||||
|
||||
# Für Vergleiche gibt es die Operatoren `==`, `!=`, `===`, `!==`, `<=`, `>=`,
|
||||
# `<` und `>`
|
||||
1 == 1 #=> true
|
||||
1 != 1 #=> false
|
||||
1 < 2 #=> true
|
||||
|
||||
# '===' und '!==' sind strikter beim Vergleich von Integern und Floats:
|
||||
1 == 1.0 #=> true
|
||||
1 === 1.0 #=> false
|
||||
|
||||
# Es ist außerdem möglich zwei verschiedene Datentypen zu vergleichen:
|
||||
1 < :hello #=> true
|
||||
|
||||
# Die gesamte Ordnung über die Datentypen ist wie folgt definiert:
|
||||
# number < atom < reference < functions < port < pid < tuple < list < bitstring
|
||||
|
||||
# Um Joe Armstrong zu zitieren: "The actual order is not important, but that a
|
||||
# total ordering is well defined is important."
|
||||
|
||||
## ---------------------------
|
||||
## -- Kontrollstrukturen
|
||||
## ---------------------------
|
||||
|
||||
# Es gibt die `if`-Verzweigung
|
||||
if false do
|
||||
"Dies wird nie jemand sehen..."
|
||||
else
|
||||
"...aber dies!"
|
||||
end
|
||||
|
||||
# ...und ebenso `unless`
|
||||
unless true do
|
||||
"Dies wird nie jemand sehen..."
|
||||
else
|
||||
"...aber dies!"
|
||||
end
|
||||
|
||||
# Du erinnerst dich an 'pattern matching'? Viele Kontrollstrukturen in Elixir
|
||||
# arbeiten damit.
|
||||
|
||||
# 'case' erlaubt es uns Werte mit vielerlei Mustern zu vergleichen.
|
||||
case {:one, :two} do
|
||||
{:four, :five} ->
|
||||
"Das wird nicht passen"
|
||||
{:one, x} ->
|
||||
"Das schon und außerdem wird es ':two' dem Wert 'x' zuweisen."
|
||||
_ ->
|
||||
"Dieser Fall greift immer."
|
||||
end
|
||||
|
||||
# Es ist eine übliche Praxis '_' einen Wert zuzuweisen, sofern dieser Wert
|
||||
# nicht weiter verwendet wird.
|
||||
# Wenn wir uns zum Beispiel nur für den Kopf einer Liste interessieren:
|
||||
[kopf | _] = [1,2,3]
|
||||
kopf #=> 1
|
||||
|
||||
# Für bessere Lesbarkeit können wir auch das Folgende machen:
|
||||
[kopf | _rest] = [:a, :b, :c]
|
||||
kopf #=> :a
|
||||
|
||||
# Mit 'cond' können diverse Bedingungen zur selben Zeit überprüft werden. Man
|
||||
# benutzt 'cond' statt viele if-Verzweigungen zu verschachteln.
|
||||
cond do
|
||||
1 + 1 == 3 ->
|
||||
"Ich werde nie aufgerufen."
|
||||
2 * 5 == 12 ->
|
||||
"Ich auch nicht."
|
||||
1 + 2 == 3 ->
|
||||
"Aber ich!"
|
||||
end
|
||||
|
||||
# Es ist üblich eine letzte Bedingung einzufügen, die immer zu wahr evaluiert.
|
||||
cond do
|
||||
1 + 1 == 3 ->
|
||||
"Ich werde nie aufgerufen."
|
||||
2 * 5 == 12 ->
|
||||
"Ich auch nicht."
|
||||
true ->
|
||||
"Aber ich! (dies ist im Grunde ein 'else')"
|
||||
end
|
||||
|
||||
# 'try/catch' wird verwendet um Werte zu fangen, die zuvor 'geworfen' wurden.
|
||||
# Das Konstrukt unterstützt außerdem eine 'after'-Klausel die aufgerufen wird,
|
||||
# egal ob zuvor ein Wert gefangen wurde.
|
||||
try do
|
||||
throw(:hello)
|
||||
catch
|
||||
nachricht -> "#{nachricht} gefangen."
|
||||
after
|
||||
IO.puts("Ich bin die 'after'-Klausel.")
|
||||
end
|
||||
#=> Ich bin die 'after'-Klausel.
|
||||
# ":hello gefangen"
|
||||
|
||||
## ---------------------------
|
||||
## -- Module und Funktionen
|
||||
## ---------------------------
|
||||
|
||||
# Anonyme Funktionen (man beachte den Punkt)
|
||||
square = fn(x) -> x * x end
|
||||
square.(5) #=> 25
|
||||
|
||||
# Anonyme Funktionen unterstützen auch 'pattern' und 'guards'. Guards erlauben
|
||||
# es die Mustererkennung zu justieren und werden mit dem Schlüsselwort 'when'
|
||||
# eingeführt:
|
||||
f = fn
|
||||
x, y when x > 0 -> x + y
|
||||
x, y -> x * y
|
||||
end
|
||||
|
||||
f.(1, 3) #=> 4
|
||||
f.(-1, 3) #=> -3
|
||||
|
||||
# Elixir bietet zahlreiche eingebaute Funktionen. Diese sind im gleichen
|
||||
# Geltungsbereich ('scope') verfügbar.
|
||||
is_number(10) #=> true
|
||||
is_list("hello") #=> false
|
||||
elem({1,2,3}, 0) #=> 1
|
||||
|
||||
# Mehrere Funktionen können in einem Modul gruppiert werden. Innerhalb eines
|
||||
# Moduls ist es möglich mit dem Schlüsselwort 'def' eine Funktion zu
|
||||
# definieren.
|
||||
defmodule Math do
|
||||
def sum(a, b) do
|
||||
a + b
|
||||
end
|
||||
|
||||
def square(x) do
|
||||
x * x
|
||||
end
|
||||
end
|
||||
|
||||
Math.sum(1, 2) #=> 3
|
||||
Math.square(3) #=> 9
|
||||
|
||||
# Um unser einfaches Mathe-Modul zu kompilieren muss es unter 'math.ex'
|
||||
# gesichert werden. Anschließend kann es mit 'elixirc' im Terminal aufgerufen
|
||||
# werden: elixirc math.ex
|
||||
|
||||
# Innerhalb eines Moduls definieren wir private Funktionen mit 'defp'. Eine
|
||||
# Funktion, die mit 'def' erstellt wurde, kann von anderen Modulen aufgerufen
|
||||
# werden; eine private Funktion kann nur lokal angesprochen werden.
|
||||
defmodule PrivateMath do
|
||||
def sum(a, b) do
|
||||
do_sum(a, b)
|
||||
end
|
||||
|
||||
defp do_sum(a, b) do
|
||||
a + b
|
||||
end
|
||||
end
|
||||
|
||||
PrivateMath.sum(1, 2) #=> 3
|
||||
# PrivateMath.do_sum(1, 2) #=> ** (UndefinedFunctionError)
|
||||
|
||||
# Auch Funktionsdeklarationen unterstützen 'guards' und Mustererkennung:
|
||||
defmodule Geometry do
|
||||
def area({:rectangle, w, h}) do
|
||||
w * h
|
||||
end
|
||||
|
||||
def area({:circle, r}) when is_number(r) do
|
||||
3.14 * r * r
|
||||
end
|
||||
end
|
||||
|
||||
Geometry.area({:rectangle, 2, 3}) #=> 6
|
||||
Geometry.area({:circle, 3}) #=> 28.25999999999999801048
|
||||
# Geometry.area({:circle, "not_a_number"})
|
||||
#=> ** (FunctionClauseError) no function clause matching in Geometry.area/1
|
||||
|
||||
# Wegen der Unveränderlichkeit von Variablen ist Rekursion ein wichtiger
|
||||
# Bestandteil von Elixir.
|
||||
defmodule Recursion do
|
||||
def sum_list([head | tail], acc) do
|
||||
sum_list(tail, acc + head)
|
||||
end
|
||||
|
||||
def sum_list([], acc) do
|
||||
acc
|
||||
end
|
||||
end
|
||||
|
||||
Recursion.sum_list([1,2,3], 0) #=> 6
|
||||
|
||||
# Elixir-Module unterstützen Attribute. Es gibt eingebaute Attribute, ebenso
|
||||
# ist es möglich eigene Attribute hinzuzufügen.
|
||||
defmodule MyMod do
|
||||
@moduledoc """
|
||||
Dies ist ein eingebautes Attribut in einem Beispiel-Modul
|
||||
"""
|
||||
|
||||
@my_data 100 # Dies ist ein selbst-definiertes Attribut.
|
||||
IO.inspect(@my_data) #=> 100
|
||||
end
|
||||
|
||||
## ---------------------------
|
||||
## -- 'Records' und Ausnahmebehandlung
|
||||
## ---------------------------
|
||||
|
||||
# 'Records' sind im Grunde Strukturen, die es erlauben einem Wert einen eigenen
|
||||
# Namen zuzuweisen.
|
||||
defrecord Person, name: nil, age: 0, height: 0
|
||||
|
||||
joe_info = Person.new(name: "Joe", age: 30, height: 180)
|
||||
#=> Person[name: "Joe", age: 30, height: 180]
|
||||
|
||||
# Zugriff auf den Wert von 'name'
|
||||
joe_info.name #=> "Joe"
|
||||
|
||||
# Den Wert von 'age' überschreiben
|
||||
joe_info = joe_info.age(31) #=> Person[name: "Joe", age: 31, height: 180]
|
||||
|
||||
# Der 'try'-Block wird zusammen mit dem 'rescue'-Schlüsselwort dazu verwendet,
|
||||
# um Ausnahmen beziehungsweise Fehler zu behandeln.
|
||||
try do
|
||||
raise "Irgendein Fehler."
|
||||
rescue
|
||||
RuntimeError -> "Laufzeit-Fehler gefangen."
|
||||
_error -> "Und dies fängt jeden Fehler."
|
||||
end
|
||||
|
||||
# Alle Ausnahmen haben das Attribut 'message'
|
||||
try do
|
||||
raise "ein Fehler"
|
||||
rescue
|
||||
x in [RuntimeError] ->
|
||||
x.message
|
||||
end
|
||||
|
||||
## ---------------------------
|
||||
## -- Nebenläufigkeit
|
||||
## ---------------------------
|
||||
|
||||
# Elixir beruht auf dem Aktoren-Model zur Behandlung der Nebenläufigkeit. Alles
|
||||
# was man braucht um in Elixir nebenläufige Programme zu schreiben sind drei
|
||||
# Primitive: Prozesse erzeugen, Nachrichten senden und Nachrichten empfangen.
|
||||
|
||||
# Um einen neuen Prozess zu erzeugen nutzen wir die 'spawn'-Funktion, die
|
||||
# wiederum eine Funktion als Argument entgegen nimmt.
|
||||
f = fn -> 2 * 2 end #=> #Function<erl_eval.20.80484245>
|
||||
spawn(f) #=> #PID<0.40.0>
|
||||
|
||||
# 'spawn' gibt eine pid (einen Identifikator des Prozesses) zurück. Diese kann
|
||||
# nun verwendet werden, um Nachrichten an den Prozess zu senden. Um
|
||||
# zu senden nutzen wir den '<-' Operator. Damit das alles Sinn macht müssen wir
|
||||
# in der Lage sein Nachrichten zu empfangen. Dies wird mit dem
|
||||
# 'receive'-Mechanismus sichergestellt:
|
||||
defmodule Geometry do
|
||||
def area_loop do
|
||||
receive do
|
||||
{:rectangle, w, h} ->
|
||||
IO.puts("Area = #{w * h}")
|
||||
area_loop()
|
||||
{:circle, r} ->
|
||||
IO.puts("Area = #{3.14 * r * r}")
|
||||
area_loop()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Kompiliere das Modul, starte einen Prozess und gib die 'area_loop' Funktion
|
||||
# in der Shell mit, etwa so:
|
||||
pid = spawn(fn -> Geometry.area_loop() end) #=> #PID<0.40.0>
|
||||
|
||||
# Sende eine Nachricht an die 'pid', die ein Muster im 'receive'-Ausdruck
|
||||
# erfüllt:
|
||||
pid <- {:rectangle, 2, 3}
|
||||
#=> Area = 6
|
||||
# {:rectangle,2,3}
|
||||
|
||||
pid <- {:circle, 2}
|
||||
#=> Area = 12.56000000000000049738
|
||||
# {:circle,2}
|
||||
|
||||
# Die Shell selbst ist ein Prozess und mit dem Schlüsselwort 'self' kann man
|
||||
# die aktuelle pid herausfinden.
|
||||
self() #=> #PID<0.27.0>
|
||||
|
||||
```
|
||||
|
||||
## Referenzen und weitere Lektüre
|
||||
|
||||
* [Getting started guide](http://elixir-lang.org/getting_started/1.html) auf der [elixir Website](http://elixir-lang.org)
|
||||
* [Elixir Documentation](http://elixir-lang.org/docs/master/)
|
||||
* ["Learn You Some Erlang for Great Good!"](http://learnyousomeerlang.com/) von Fred Hebert
|
||||
* "Programming Erlang: Software for a Concurrent World" von Joe Armstrong
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,263 +1,263 @@
|
||||
---
|
||||
category: tool
|
||||
tool: make
|
||||
contributors:
|
||||
- ["Robert Steed", "https://github.com/robochat"]
|
||||
- ["Stephan Fuhrmann", "https://github.com/sfuhrm"]
|
||||
translators:
|
||||
- ["Martin Schimandl", "https://github.com/Git-Jiro"]
|
||||
filename: Makefile-de
|
||||
lang: de-de
|
||||
---
|
||||
|
||||
Eine Makefile definiert einen Graphen von Regeln um ein Ziel (oder Ziele)
|
||||
zu erzeugen. Es dient dazu, die geringste Menge an Arbeit zu verrichten um
|
||||
ein Ziel in Einklang mit dem Quellcode zu bringen. Make wurde berühmterweise
|
||||
von Stuart Feldman 1976 übers Wochenende geschrieben. Make ist noch immer
|
||||
sehr verbreitet (vorallem im Unix Umfeld) obwohl es bereits sehr viel
|
||||
Konkurrenz und Kritik zu Make gibt.
|
||||
|
||||
Es gibt eine Vielzahl an Varianten von Make, dieser Artikel beschäftigt sich
|
||||
mit der Version GNU Make. Diese Version ist Standard auf Linux.
|
||||
|
||||
```make
|
||||
|
||||
# Kommentare können so geschrieben werden.
|
||||
|
||||
# Dateien sollten Makefile heißen, denn dann können sie als `make <ziel>`
|
||||
# aufgerufen werden. Ansonsten muss `make -f "dateiname" <ziel>` verwendet
|
||||
# werden.
|
||||
|
||||
# Warnung - Es sollten nur TABULATOREN zur Einrückung im Makefile verwendet
|
||||
# werden. Niemals Leerzeichen!
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Grundlagen
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# Eine Regel - Diese Regel wird nur abgearbeitet wenn die Datei file0.txt
|
||||
# nicht existiert.
|
||||
file0.txt:
|
||||
echo "foo" > file0.txt
|
||||
# Selbst Kommentare in der 'Rezept' Sektion werden an die Shell
|
||||
# weitergegeben. Versuche `make file0.txt` oder einfach `make`
|
||||
# die erste Regel ist die Standard-Regel.
|
||||
|
||||
|
||||
# Diese Regel wird nur abgearbeitet, wenn file0.txt aktueller als file1.txt ist.
|
||||
file1.txt: file0.txt
|
||||
cat file0.txt > file1.txt
|
||||
# Verwende die selben Quoting-Regeln wie die Shell
|
||||
@cat file0.txt >> file1.txt
|
||||
# @ unterdrückt die Ausgabe des Befehls an stdout.
|
||||
-@echo 'hello'
|
||||
# - bedeutet, dass Make die Abarbeitung fortsetzt auch wenn Fehler
|
||||
# passieren.
|
||||
# Versuche `make file1.txt` auf der Kommandozeile.
|
||||
|
||||
# Eine Regel kann mehrere Ziele und mehrere Voraussetzungen haben.
|
||||
file2.txt file3.txt: file0.txt file1.txt
|
||||
touch file2.txt
|
||||
touch file3.txt
|
||||
|
||||
# Make wird sich beschweren, wenn es mehrere Rezepte für die gleiche Regel gibt.
|
||||
# Leere Rezepte zählen nicht und können dazu verwendet werden weitere
|
||||
# Voraussetzungen hinzuzufügen.
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Phony-Ziele
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# Ein Phony-Ziel ist ein Ziel, das keine Datei ist.
|
||||
# Es wird nie aktuell sein, daher wird Make immer versuchen, es abzuarbeiten
|
||||
all: maker process
|
||||
|
||||
# Es ist erlaubt Dinge ausserhalb der Reihenfolge zu deklarieren.
|
||||
maker:
|
||||
touch ex0.txt ex1.txt
|
||||
|
||||
# Um das Fehlschlagen von Phony-Regeln zu vermeiden wenn eine echte Datei den
|
||||
# selben namen wie ein Phony-Ziel hat:
|
||||
.PHONY: all maker process
|
||||
# Das ist ein spezielles Ziel. Es gibt noch ein paar mehr davon.
|
||||
|
||||
# Eine Regel mit einem Phony-Ziel als Voraussetzung wird immer abgearbeitet
|
||||
ex0.txt ex1.txt: maker
|
||||
|
||||
# Häufige Phony-Ziele sind: all make clean install ...
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Automatische Variablen & Wildcards
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
process: file*.txt # Eine Wildcard um Dateinamen zu vergleichen
|
||||
@echo $^ # $^ ist eine Variable die eine Liste aller
|
||||
# Voraussetzungen enthält.
|
||||
@echo $@ # Namen des Ziels ausgeben.
|
||||
#(Bei mehreren Ziel-Regeln enthält $@ den Verursacher der Abarbeitung
|
||||
#der Regel.)
|
||||
@echo $< # Die erste Voraussetzung aus der Liste
|
||||
@echo $? # Nur die Voraussetzungen, die nicht aktuell sind.
|
||||
@echo $+ # Alle Voraussetzungen inklusive Duplikate (nicht wie Üblich)
|
||||
#@echo $| # Alle 'order only' Voraussetzungen
|
||||
|
||||
# Selbst wenn wir die Voraussetzungen der Regel aufteilen, $^ wird sie finden.
|
||||
process: ex1.txt file0.txt
|
||||
# ex1.txt wird gefunden werden, aber file0.txt wird dedupliziert.
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Muster
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# Mit Mustern kann man make beibringen wie Dateien in andere Dateien
|
||||
# umgewandelt werden.
|
||||
|
||||
%.png: %.svg
|
||||
inkscape --export-png $^
|
||||
|
||||
# Muster-Vergleichs-Regeln werden nur abgearbeitet, wenn make entscheidet das
|
||||
# Ziel zu erzeugen
|
||||
|
||||
# Verzeichnis-Pfade werden normalerweise bei Muster-Vergleichs-Regeln ignoriert.
|
||||
# Aber make wird versuchen die am besten passende Regel zu verwenden.
|
||||
small/%.png: %.svg
|
||||
inkscape --export-png --export-dpi 30 $^
|
||||
|
||||
# Make wird die letzte Version einer Muster-Vergleichs-Regel verwenden, die es
|
||||
# findet.
|
||||
%.png: %.svg
|
||||
@echo this rule is chosen
|
||||
|
||||
# Allerdings wird make die erste Muster-Vergleicher-Regel verwenden, die das
|
||||
# Ziel erzeugen kann.
|
||||
%.png: %.ps
|
||||
@echo this rule is not chosen if *.svg and *.ps are both present
|
||||
|
||||
# Make hat bereits ein paar eingebaute Muster-Vergleichs-Regelen. Zum Beispiel
|
||||
# weiß Make wie man aus *.c Dateien *.o Dateien erzeugt.
|
||||
|
||||
# Ältere Versionen von Make verwenden möglicherweise Suffix-Regeln anstatt
|
||||
# Muster-Vergleichs-Regeln.
|
||||
.png.ps:
|
||||
@echo this rule is similar to a pattern rule.
|
||||
|
||||
# Aktivieren der Suffix-Regel
|
||||
.SUFFIXES: .png
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Variablen
|
||||
#-----------------------------------------------------------------------
|
||||
# auch Makros genannt.
|
||||
|
||||
# Variablen sind im Grunde genommen Zeichenketten-Typen.
|
||||
|
||||
name = Ted
|
||||
name2="Sarah"
|
||||
|
||||
echo:
|
||||
@echo $(name)
|
||||
@echo ${name2}
|
||||
@echo $name # Das funktioniert nicht, wird als $(n)ame behandelt.
|
||||
@echo $(name3) # Unbekannte Variablen werden als leere Zeichenketten behandelt.
|
||||
|
||||
# Es git 4 Stellen um Variablen zu setzen.
|
||||
# In Reihenfolge der Priorität von höchster zu niedrigster:
|
||||
# 1: Befehls-Zeilen Argumente
|
||||
# 2: Makefile
|
||||
# 3: Shell Umbebungs-Variablen - Make importiert diese automatisch.
|
||||
# 3: MAke hat einige vordefinierte Variablen.
|
||||
|
||||
name4 ?= Jean
|
||||
# Setze die Variable nur wenn es eine gleichnamige Umgebungs-Variable noch
|
||||
# nicht gibt.
|
||||
|
||||
override name5 = David
|
||||
# Verhindert, dass Kommando-Zeilen Argumente diese Variable ändern können.
|
||||
|
||||
name4 +=grey
|
||||
# Werte an eine Variable anhängen (inkludiert Leerzeichen).
|
||||
|
||||
# Muster-Spezifische Variablen Werte (GNU Erweiterung).
|
||||
echo: name2 = Sara # Wahr innerhalb der passenden Regel und auch innerhalb
|
||||
# rekursiver Voraussetzungen (ausser wenn es den Graphen zerstören
|
||||
# kann, wenn es zu kompilizert wird!)
|
||||
|
||||
# Ein paar Variablen, die von Make automatisch definiert werden.
|
||||
echo_inbuilt:
|
||||
echo $(CC)
|
||||
echo ${CXX}
|
||||
echo $(FC)
|
||||
echo ${CFLAGS}
|
||||
echo $(CPPFLAGS)
|
||||
echo ${CXXFLAGS}
|
||||
echo $(LDFLAGS)
|
||||
echo ${LDLIBS}
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Variablen 2
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# Der erste Typ von Variablen wird bei jeder Verwendung ausgewertet.
|
||||
# Das kann aufwendig sein, daher exisitert ein zweiter Typ von Variablen.
|
||||
# Diese werden nur einmal ausgewertet. (Das ist eine GNU make Erweiterung)
|
||||
|
||||
var := hello
|
||||
var2 ::= $(var) hello
|
||||
#:= und ::= sind äquivalent.
|
||||
|
||||
# Diese Variablen werden prozedural ausgwertet (in der Reihenfolge in der sie
|
||||
# auftauchen), die stehen daher im wiederspruch zum Rest der Sprache!
|
||||
|
||||
# Das funktioniert nicht
|
||||
var3 ::= $(var4) and good luck
|
||||
var4 ::= good night
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Funktionen
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# Make verfügt über eine Vielzahl von Funktionen.
|
||||
|
||||
sourcefiles = $(wildcard *.c */*.c)
|
||||
objectfiles = $(patsubst %.c,%.o,$(sourcefiles))
|
||||
|
||||
# Das Format ist $(func arg0,arg1,arg2...)
|
||||
|
||||
# Ein paar Beispiele
|
||||
ls: * src/*
|
||||
@echo $(filter %.txt, $^)
|
||||
@echo $(notdir $^)
|
||||
@echo $(join $(dir $^),$(notdir $^))
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Direktiven
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# Inkludiere andere Makefile, sehr praktisch für platformspezifischen Code
|
||||
include foo.mk
|
||||
|
||||
sport = tennis
|
||||
# Konditionale kompiliereung
|
||||
report:
|
||||
ifeq ($(sport),tennis)
|
||||
@echo 'game, set, match'
|
||||
else
|
||||
@echo "They think it's all over; it is now"
|
||||
endif
|
||||
|
||||
# Es gibt auch ifneq, ifdef, ifndef
|
||||
|
||||
foo = true
|
||||
|
||||
ifdef $(foo)
|
||||
bar = 'hello'
|
||||
endif
|
||||
```
|
||||
|
||||
|
||||
### Mehr Resourcen
|
||||
|
||||
+ [gnu make documentation](https://www.gnu.org/software/make/manual/)
|
||||
+ [software carpentry tutorial](http://swcarpentry.github.io/make-novice/)
|
||||
+ learn C the hard way [ex2](http://c.learncodethehardway.org/book/ex2.html) [ex28](http://c.learncodethehardway.org/book/ex28.html)
|
||||
|
||||
---
|
||||
category: tool
|
||||
tool: make
|
||||
contributors:
|
||||
- ["Robert Steed", "https://github.com/robochat"]
|
||||
- ["Stephan Fuhrmann", "https://github.com/sfuhrm"]
|
||||
translators:
|
||||
- ["Martin Schimandl", "https://github.com/Git-Jiro"]
|
||||
filename: Makefile-de
|
||||
lang: de-de
|
||||
---
|
||||
|
||||
Eine Makefile definiert einen Graphen von Regeln um ein Ziel (oder Ziele)
|
||||
zu erzeugen. Es dient dazu, die geringste Menge an Arbeit zu verrichten um
|
||||
ein Ziel in Einklang mit dem Quellcode zu bringen. Make wurde berühmterweise
|
||||
von Stuart Feldman 1976 übers Wochenende geschrieben. Make ist noch immer
|
||||
sehr verbreitet (vorallem im Unix Umfeld) obwohl es bereits sehr viel
|
||||
Konkurrenz und Kritik zu Make gibt.
|
||||
|
||||
Es gibt eine Vielzahl an Varianten von Make, dieser Artikel beschäftigt sich
|
||||
mit der Version GNU Make. Diese Version ist Standard auf Linux.
|
||||
|
||||
```make
|
||||
|
||||
# Kommentare können so geschrieben werden.
|
||||
|
||||
# Dateien sollten Makefile heißen, denn dann können sie als `make <ziel>`
|
||||
# aufgerufen werden. Ansonsten muss `make -f "dateiname" <ziel>` verwendet
|
||||
# werden.
|
||||
|
||||
# Warnung - Es sollten nur TABULATOREN zur Einrückung im Makefile verwendet
|
||||
# werden. Niemals Leerzeichen!
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Grundlagen
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# Eine Regel - Diese Regel wird nur abgearbeitet wenn die Datei file0.txt
|
||||
# nicht existiert.
|
||||
file0.txt:
|
||||
echo "foo" > file0.txt
|
||||
# Selbst Kommentare in der 'Rezept' Sektion werden an die Shell
|
||||
# weitergegeben. Versuche `make file0.txt` oder einfach `make`
|
||||
# die erste Regel ist die Standard-Regel.
|
||||
|
||||
|
||||
# Diese Regel wird nur abgearbeitet, wenn file0.txt aktueller als file1.txt ist.
|
||||
file1.txt: file0.txt
|
||||
cat file0.txt > file1.txt
|
||||
# Verwende die selben Quoting-Regeln wie die Shell
|
||||
@cat file0.txt >> file1.txt
|
||||
# @ unterdrückt die Ausgabe des Befehls an stdout.
|
||||
-@echo 'hello'
|
||||
# - bedeutet, dass Make die Abarbeitung fortsetzt auch wenn Fehler
|
||||
# passieren.
|
||||
# Versuche `make file1.txt` auf der Kommandozeile.
|
||||
|
||||
# Eine Regel kann mehrere Ziele und mehrere Voraussetzungen haben.
|
||||
file2.txt file3.txt: file0.txt file1.txt
|
||||
touch file2.txt
|
||||
touch file3.txt
|
||||
|
||||
# Make wird sich beschweren, wenn es mehrere Rezepte für die gleiche Regel gibt.
|
||||
# Leere Rezepte zählen nicht und können dazu verwendet werden weitere
|
||||
# Voraussetzungen hinzuzufügen.
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Phony-Ziele
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# Ein Phony-Ziel ist ein Ziel, das keine Datei ist.
|
||||
# Es wird nie aktuell sein, daher wird Make immer versuchen, es abzuarbeiten
|
||||
all: maker process
|
||||
|
||||
# Es ist erlaubt Dinge ausserhalb der Reihenfolge zu deklarieren.
|
||||
maker:
|
||||
touch ex0.txt ex1.txt
|
||||
|
||||
# Um das Fehlschlagen von Phony-Regeln zu vermeiden wenn eine echte Datei den
|
||||
# selben namen wie ein Phony-Ziel hat:
|
||||
.PHONY: all maker process
|
||||
# Das ist ein spezielles Ziel. Es gibt noch ein paar mehr davon.
|
||||
|
||||
# Eine Regel mit einem Phony-Ziel als Voraussetzung wird immer abgearbeitet
|
||||
ex0.txt ex1.txt: maker
|
||||
|
||||
# Häufige Phony-Ziele sind: all make clean install ...
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Automatische Variablen & Wildcards
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
process: file*.txt # Eine Wildcard um Dateinamen zu vergleichen
|
||||
@echo $^ # $^ ist eine Variable die eine Liste aller
|
||||
# Voraussetzungen enthält.
|
||||
@echo $@ # Namen des Ziels ausgeben.
|
||||
#(Bei mehreren Ziel-Regeln enthält $@ den Verursacher der Abarbeitung
|
||||
#der Regel.)
|
||||
@echo $< # Die erste Voraussetzung aus der Liste
|
||||
@echo $? # Nur die Voraussetzungen, die nicht aktuell sind.
|
||||
@echo $+ # Alle Voraussetzungen inklusive Duplikate (nicht wie Üblich)
|
||||
#@echo $| # Alle 'order only' Voraussetzungen
|
||||
|
||||
# Selbst wenn wir die Voraussetzungen der Regel aufteilen, $^ wird sie finden.
|
||||
process: ex1.txt file0.txt
|
||||
# ex1.txt wird gefunden werden, aber file0.txt wird dedupliziert.
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Muster
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# Mit Mustern kann man make beibringen wie Dateien in andere Dateien
|
||||
# umgewandelt werden.
|
||||
|
||||
%.png: %.svg
|
||||
inkscape --export-png $^
|
||||
|
||||
# Muster-Vergleichs-Regeln werden nur abgearbeitet, wenn make entscheidet das
|
||||
# Ziel zu erzeugen
|
||||
|
||||
# Verzeichnis-Pfade werden normalerweise bei Muster-Vergleichs-Regeln ignoriert.
|
||||
# Aber make wird versuchen die am besten passende Regel zu verwenden.
|
||||
small/%.png: %.svg
|
||||
inkscape --export-png --export-dpi 30 $^
|
||||
|
||||
# Make wird die letzte Version einer Muster-Vergleichs-Regel verwenden, die es
|
||||
# findet.
|
||||
%.png: %.svg
|
||||
@echo this rule is chosen
|
||||
|
||||
# Allerdings wird make die erste Muster-Vergleicher-Regel verwenden, die das
|
||||
# Ziel erzeugen kann.
|
||||
%.png: %.ps
|
||||
@echo this rule is not chosen if *.svg and *.ps are both present
|
||||
|
||||
# Make hat bereits ein paar eingebaute Muster-Vergleichs-Regelen. Zum Beispiel
|
||||
# weiß Make wie man aus *.c Dateien *.o Dateien erzeugt.
|
||||
|
||||
# Ältere Versionen von Make verwenden möglicherweise Suffix-Regeln anstatt
|
||||
# Muster-Vergleichs-Regeln.
|
||||
.png.ps:
|
||||
@echo this rule is similar to a pattern rule.
|
||||
|
||||
# Aktivieren der Suffix-Regel
|
||||
.SUFFIXES: .png
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Variablen
|
||||
#-----------------------------------------------------------------------
|
||||
# auch Makros genannt.
|
||||
|
||||
# Variablen sind im Grunde genommen Zeichenketten-Typen.
|
||||
|
||||
name = Ted
|
||||
name2="Sarah"
|
||||
|
||||
echo:
|
||||
@echo $(name)
|
||||
@echo ${name2}
|
||||
@echo $name # Das funktioniert nicht, wird als $(n)ame behandelt.
|
||||
@echo $(name3) # Unbekannte Variablen werden als leere Zeichenketten behandelt.
|
||||
|
||||
# Es git 4 Stellen um Variablen zu setzen.
|
||||
# In Reihenfolge der Priorität von höchster zu niedrigster:
|
||||
# 1: Befehls-Zeilen Argumente
|
||||
# 2: Makefile
|
||||
# 3: Shell Umbebungs-Variablen - Make importiert diese automatisch.
|
||||
# 3: MAke hat einige vordefinierte Variablen.
|
||||
|
||||
name4 ?= Jean
|
||||
# Setze die Variable nur wenn es eine gleichnamige Umgebungs-Variable noch
|
||||
# nicht gibt.
|
||||
|
||||
override name5 = David
|
||||
# Verhindert, dass Kommando-Zeilen Argumente diese Variable ändern können.
|
||||
|
||||
name4 +=grey
|
||||
# Werte an eine Variable anhängen (inkludiert Leerzeichen).
|
||||
|
||||
# Muster-Spezifische Variablen Werte (GNU Erweiterung).
|
||||
echo: name2 = Sara # Wahr innerhalb der passenden Regel und auch innerhalb
|
||||
# rekursiver Voraussetzungen (ausser wenn es den Graphen zerstören
|
||||
# kann, wenn es zu kompilizert wird!)
|
||||
|
||||
# Ein paar Variablen, die von Make automatisch definiert werden.
|
||||
echo_inbuilt:
|
||||
echo $(CC)
|
||||
echo ${CXX}
|
||||
echo $(FC)
|
||||
echo ${CFLAGS}
|
||||
echo $(CPPFLAGS)
|
||||
echo ${CXXFLAGS}
|
||||
echo $(LDFLAGS)
|
||||
echo ${LDLIBS}
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Variablen 2
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# Der erste Typ von Variablen wird bei jeder Verwendung ausgewertet.
|
||||
# Das kann aufwendig sein, daher exisitert ein zweiter Typ von Variablen.
|
||||
# Diese werden nur einmal ausgewertet. (Das ist eine GNU make Erweiterung)
|
||||
|
||||
var := hello
|
||||
var2 ::= $(var) hello
|
||||
#:= und ::= sind äquivalent.
|
||||
|
||||
# Diese Variablen werden prozedural ausgwertet (in der Reihenfolge in der sie
|
||||
# auftauchen), die stehen daher im wiederspruch zum Rest der Sprache!
|
||||
|
||||
# Das funktioniert nicht
|
||||
var3 ::= $(var4) and good luck
|
||||
var4 ::= good night
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Funktionen
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# Make verfügt über eine Vielzahl von Funktionen.
|
||||
|
||||
sourcefiles = $(wildcard *.c */*.c)
|
||||
objectfiles = $(patsubst %.c,%.o,$(sourcefiles))
|
||||
|
||||
# Das Format ist $(func arg0,arg1,arg2...)
|
||||
|
||||
# Ein paar Beispiele
|
||||
ls: * src/*
|
||||
@echo $(filter %.txt, $^)
|
||||
@echo $(notdir $^)
|
||||
@echo $(join $(dir $^),$(notdir $^))
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Direktiven
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# Inkludiere andere Makefile, sehr praktisch für platformspezifischen Code
|
||||
include foo.mk
|
||||
|
||||
sport = tennis
|
||||
# Konditionale kompiliereung
|
||||
report:
|
||||
ifeq ($(sport),tennis)
|
||||
@echo 'game, set, match'
|
||||
else
|
||||
@echo "They think it's all over; it is now"
|
||||
endif
|
||||
|
||||
# Es gibt auch ifneq, ifdef, ifndef
|
||||
|
||||
foo = true
|
||||
|
||||
ifdef $(foo)
|
||||
bar = 'hello'
|
||||
endif
|
||||
```
|
||||
|
||||
|
||||
### Mehr Resourcen
|
||||
|
||||
+ [gnu make documentation](https://www.gnu.org/software/make/manual/)
|
||||
+ [software carpentry tutorial](http://swcarpentry.github.io/make-novice/)
|
||||
+ learn C the hard way [ex2](http://c.learncodethehardway.org/book/ex2.html) [ex28](http://c.learncodethehardway.org/book/ex28.html)
|
||||
|
||||
|
@ -1,281 +1,281 @@
|
||||
---
|
||||
category: tool
|
||||
tool: docker
|
||||
filename: docker.bat
|
||||
contributors:
|
||||
- ["Ruslan López", "http://javapro.org/"]
|
||||
- ["Michael Chen", "https://github.com/ML-Chen"]
|
||||
- ["Akshita Dixit", "https://github.com/akshitadixit"]
|
||||
- ["Marcel Ribeiro-Dantas", "https://github.com/mribeirodantas"]
|
||||
---
|
||||
|
||||
Docker is a tool that helps you build, test, ship and run applications
|
||||
seamlessly across various machines. It replicates the environment our software
|
||||
needs on any machine. You can get Docker for your machine from
|
||||
https://docs.docker.com/get-docker/
|
||||
|
||||
It has grown in popularity over the last decade due to being lightweight and
|
||||
fast as compared to virtual-machines that are bulky and slow. Unlike VMs, docker
|
||||
does not need a full blown OS of its own to be loaded to start and does not
|
||||
compete for resources other than what the application it is running will use.
|
||||
VMs on the other hand are pretty resource intensive on our processors, disks and
|
||||
memory hence running multiple VMs for various applications becomes a challenge
|
||||
in a limited capacity architecture.
|
||||
|
||||
<pre>
|
||||
┌────────────────────────┐ ┌───────────────────────┐
|
||||
│ ┌───────────┐ │ │ ┌───────────┐ │
|
||||
│ │ App │ │ │ │ App │ │
|
||||
│ └───────────┘ │ │ └───────────┘ │
|
||||
│ ┌────────┐ ┌────────┐ │ │ ┌────────┐ ┌───────┐ │
|
||||
│ │ Libs │ │ Deps │ │ │ │ Libs │ │ Deps │ │
|
||||
│ └────────┘ └────────┘ │ │ └────────┘ └───────┘ │
|
||||
│ ┌───────────────────┐ │ │ ┌──────────────────┐ │
|
||||
│ │ Guest OS │ │ │ │ Guest OS │ │
|
||||
│ └───────────────────┘ │ │ └──────────────────┘ │
|
||||
│ VM1 │ │ VM2 │
|
||||
└────────────────────────┘ └───────────────────────┘
|
||||
┌──────────────────────────────────────────────────┐
|
||||
│ Hypervisor │
|
||||
└──────────────────────────────────────────────────┘
|
||||
┌──────────────────────────────────────────────────┐
|
||||
│ Host OS │
|
||||
└──────────────────────────────────────────────────┘
|
||||
┌──────────────────────────────────────────────────┐
|
||||
│ Hardware Infrastructure │
|
||||
└──────────────────────────────────────────────────┘
|
||||
(VM based architecture)
|
||||
|
||||
┌────────────────────────┐ ┌───────────────────────┐
|
||||
│ ┌───────────┐ │ │ ┌───────────┐ │
|
||||
│ │ App │ │ │ │ App │ │
|
||||
│ └───────────┘ │ │ └───────────┘ │
|
||||
│ ┌────────┐ ┌────────┐ │ │ ┌────────┐ ┌───────┐ │
|
||||
│ │ Libs │ │ Deps │ │ │ │ Libs │ │ Deps │ │
|
||||
│ └────────┘ └────────┘ │ │ └────────┘ └───────┘ │
|
||||
│ Container1 │ │ Container2 │
|
||||
└────────────────────────┘ └───────────────────────┘
|
||||
┌──────────────────────────────────────────────────┐
|
||||
│ Docker │
|
||||
└──────────────────────────────────────────────────┘
|
||||
┌──────────────────────────────────────────────────┐
|
||||
│ OS │
|
||||
└──────────────────────────────────────────────────┘
|
||||
┌──────────────────────────────────────────────────┐
|
||||
│ Hardware Infrastructure │
|
||||
└──────────────────────────────────────────────────┘
|
||||
(Docker based architecture)
|
||||
|
||||
</pre>
|
||||
|
||||
Couple of terms we will encounter frequently are Docker Images and Docker
|
||||
Containers. Images are packages or templates of containers all stored in a
|
||||
container registry such as [Docker Hub](https://hub.docker.com/). Containers
|
||||
are standalone, executable instances of these images which include code,
|
||||
runtime, system tools, system libraries and settings - everything required to
|
||||
get the software up and running. Coming to Docker, it follows a client-server
|
||||
architecture wherein the CLI client communicates with the server component,
|
||||
which here is, the Docker Engine using RESTful API to issue commands.
|
||||
|
||||
## The Docker CLI
|
||||
```bash
|
||||
# after installing Docker from https://docs.docker.com/get-docker/
|
||||
# To list available commands, either run `docker` with no parameters or execute
|
||||
# `docker help`
|
||||
$ docker
|
||||
|
||||
>>> docker [OPTIONS] COMMAND [ARG...]
|
||||
docker [ --help | -v | --version ]
|
||||
|
||||
A self-sufficient runtime for containers.
|
||||
|
||||
Options:
|
||||
--config string Location of client config files (default "/root/.docker")
|
||||
-c, --context string Name of the context to use to connect to the daemon (overrides DOCKER_HOST env var and default context set with "docker context use")
|
||||
-D, --debug Enable debug mode
|
||||
--help Print usage
|
||||
-H, --host value Daemon socket(s) to connect to (default [])
|
||||
-l, --log-level string Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info")
|
||||
--tls Use TLS; implied by --tlsverify
|
||||
--tlscacert string Trust certs signed only by this CA (default "/root/.docker/ca.pem")
|
||||
--tlscert string Path to TLS certificate file (default "/root/.docker/cert.pem")
|
||||
--tlskey string Path to TLS key file (default "/root/.docker/key.pem")
|
||||
--tlsverify Use TLS and verify the remote
|
||||
-v, --version Print version information and quit
|
||||
|
||||
Commands:
|
||||
attach Attach to a running container
|
||||
# […]
|
||||
|
||||
$ docker run hello-world
|
||||
# `docker run <container-name>` is used to run a container, it will pull the
|
||||
# images from Docker Hub if they don't already exist in your system. Here the
|
||||
# docker client connects to the daemon which in turn pulls the "hello-world"
|
||||
# image from the Docker Hub. The daemon then builds a new container from the
|
||||
# image which runs the executable that produces the output streamed back to the
|
||||
# client that we see on our terminals.
|
||||
|
||||
$ docker run -d ubuntu sleep 60s
|
||||
# The -d (or --detach) flag is when we want to run a container in the background
|
||||
# and return back to the terminal. Here we detach an ubuntu container from the
|
||||
# terminal, the output should be the id and the command exits. If we check
|
||||
# running containers, we should still see ours there:
|
||||
# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
# 133261b4894a ubuntu "sleep 60s" 3 seconds ago Up 2 seconds vigorous_gould
|
||||
|
||||
$ docker run <container-id> -p 3000:8000
|
||||
# The -p (or --publish) flag is used to expose port 8000 inside the container to
|
||||
# port 3000 outside the container. This is because the app inside the container
|
||||
# runs in isolation, hence the port 8000 where the app runs is private to the
|
||||
# container.
|
||||
|
||||
$ docker run -i
|
||||
# or
|
||||
$ docker run -it
|
||||
# Docker runs our containers in a non-interactive mode i.e. they do not accept
|
||||
# inputs or work dynamically while running. The -i flag keeps input open to the
|
||||
# container, and the -t flag creates a pseudo-terminal that the shell can attach
|
||||
# to (can be combined as -it)
|
||||
|
||||
$ docker ps -a
|
||||
# The `docker ps` command only shows running containers by default. To see all
|
||||
# containers, use the -a (or --all) flag
|
||||
# Running the above command should output something similar in the terminal:
|
||||
# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
# 82f84bf6912b hello-world "/hello" 9 minutes ago Exited (0) 9 minutes ago eloquent_sammet
|
||||
|
||||
|
||||
$ docker stop hello-world
|
||||
# or
|
||||
$ docker start hello-world
|
||||
# The stop command simply stops one or more containers, and the start command
|
||||
# starts the container(s) up again! `docker start -a ubuntu` will attach our
|
||||
# detached container back to the terminal i.e. runs in the foreground
|
||||
|
||||
$ docker create alpine
|
||||
# `docker create` creates a new container for us with the image specified (here,
|
||||
# alpine), the container does not auto-start unlike `docker run`. This command
|
||||
# is used to set up a container configuration and then `docker start` to shoot
|
||||
# it up when required. Note that the status is "Created":
|
||||
# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
# 4c71c727c73d alpine "/bin/sh" 29 seconds ago Created naughty_ritchie
|
||||
|
||||
$ docker rm 82f84
|
||||
# Removes one or more containers using their container ID.
|
||||
# P.S.: we can use only the first few characters of the entire ID to identify
|
||||
# containers
|
||||
|
||||
$ docker images
|
||||
# Displays all images and their information, created here means the latest image
|
||||
# tag updated on Docker Hub:
|
||||
# REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
# ubuntu latest a8780b506fa4 9 days ago 77.8MB
|
||||
# alpine latest 9c6f07244728 3 months ago 5.54MB
|
||||
# hello-world latest feb5d9fea6a5 13 months ago 13.3kB
|
||||
|
||||
$ docker rmi
|
||||
# Removes one or more images from your system which do not have their instances
|
||||
# (or containers as we know them) running. If the image has an attached
|
||||
# container, either delete the container first or use the -f (or --force) flag
|
||||
# to forcefully delete both the container and image.
|
||||
|
||||
$ docker pull busybox
|
||||
# The pull command downloads the specified image on our system from Docker Hub.
|
||||
|
||||
$ docker exec -it 7b272 bash
|
||||
# This command is used to run a command in the running container's default
|
||||
# directory. Here 7b272 was our ubuntu container and the above command would
|
||||
# help us interact with the container by opening a bash session.
|
||||
|
||||
$ docker logs <container-id>
|
||||
# Displays the information logged by the specified container
|
||||
# root@7b27222e4bb7:/# whoami
|
||||
# root
|
||||
# root@7b27222e4bb7:/# pwd
|
||||
# /
|
||||
# root@7b27222e4bb7:/# ls
|
||||
# bin boot dev etc home lib lib32 lib64 libx3 srv sys tmp usr var
|
||||
# root@7b27222e4bb7:/# exit
|
||||
# exit
|
||||
|
||||
# More commands can be found at https://docs.docker.com/engine/reference/commandline/docker/
|
||||
```
|
||||
## The Dockerfile
|
||||
The Dockerfile is a blueprint of a Docker image. We can mention the artifacts
|
||||
from our application along with their configurations into this file in the
|
||||
specific syntax to let anyone create a Docker image of our application.
|
||||
|
||||
### A few things to keep in mind:
|
||||
* It is always strictly named `Dockerfile` without any extensions
|
||||
* We have to build our custom image on top of some already available Docker base
|
||||
image. (there is an empty image called `scratch` which literally lets you build
|
||||
an image from scratch)
|
||||
* All capitalised commands are part of the syntax, they are not case-sensitive
|
||||
but used like a convention
|
||||
* Below is a sample Dockerfile but you can read in depth from the [official docs](https://docs.docker.com/engine/reference/builder/).
|
||||
|
||||
```Dockerfile
|
||||
FROM <base-image>
|
||||
# define base image
|
||||
|
||||
ENV USERNAME='admin'\
|
||||
PWD='****'
|
||||
# optionally define environmental variables
|
||||
|
||||
RUN apt-get update
|
||||
# run linux commands inside container env, does not affect host env
|
||||
# This executes during the time of image creation
|
||||
|
||||
COPY <src> <target>
|
||||
# executes on the host, copies files from src (usually on the host) to target
|
||||
# on the container
|
||||
|
||||
ENTRYPOINT ["some-script.sh"]
|
||||
# executes an entire script as an entrypoint
|
||||
|
||||
CMD [<args>,...]
|
||||
# always part of dockerfile, introduces entry point linux command e.g.
|
||||
# `CMD node server.js`
|
||||
# This executes after image creation only when the container from the image
|
||||
# is running.
|
||||
```
|
||||
### Build your images
|
||||
Use the `docker build` command after wrapping your application into a Docker
|
||||
image to run ( or build) it.
|
||||
|
||||
```bash
|
||||
|
||||
$ docker build <path-to-dockerfile>
|
||||
# used to build an image from the specified Dockerfile
|
||||
# instead of path we could also specify a URL
|
||||
# -t tag is optional and used to name and tag your images for e.g.
|
||||
# `$ docker build -t my-image:0.1 ./home/app`
|
||||
# rebuild images everytime you make changes in the dockerfile
|
||||
```
|
||||
|
||||
## Push your image to DockerHub
|
||||
If you want your application's Docker image to be made publicly available for
|
||||
any Docker user, you might wanna push it to the [Docker Hub](https://hub.docker.com/) which is a
|
||||
registry of Docker images. Make sure you have an account with a username and
|
||||
password on Docker Hub.
|
||||
|
||||
When pushing an image to Docker Hub, we must specify our Docker Hub username
|
||||
as part of the source image name. We need to create the target image with the
|
||||
tag name of username/image-name much like GitHub repositories.
|
||||
|
||||
```bash
|
||||
$ docker login
|
||||
# to login to Docker Hub using your username and password
|
||||
|
||||
$ docker tag <src-image>[:<src-tag>] <target-image>[:<target-tag>]
|
||||
# this tags a local src-image to a public target-image
|
||||
# e.g. `docker tag my-sample-app:1.0.0 akshitadixit/my-sample-app`
|
||||
# if tags are not specified, they're defaulted to `latest`
|
||||
|
||||
$ docker push <target-image>[:<target-tag>]
|
||||
# uploads our image to Docker Hub
|
||||
# e.g. `docker push akshitadixit/my-sample-app`
|
||||
# this image will be accessible under your profile's repositories as
|
||||
# `https://hub.docker.com/r/username/image-name`
|
||||
|
||||
```
|
||||
---
|
||||
category: tool
|
||||
tool: docker
|
||||
filename: docker.bat
|
||||
contributors:
|
||||
- ["Ruslan López", "http://javapro.org/"]
|
||||
- ["Michael Chen", "https://github.com/ML-Chen"]
|
||||
- ["Akshita Dixit", "https://github.com/akshitadixit"]
|
||||
- ["Marcel Ribeiro-Dantas", "https://github.com/mribeirodantas"]
|
||||
---
|
||||
|
||||
Docker is a tool that helps you build, test, ship and run applications
|
||||
seamlessly across various machines. It replicates the environment our software
|
||||
needs on any machine. You can get Docker for your machine from
|
||||
https://docs.docker.com/get-docker/
|
||||
|
||||
It has grown in popularity over the last decade due to being lightweight and
|
||||
fast as compared to virtual-machines that are bulky and slow. Unlike VMs, docker
|
||||
does not need a full blown OS of its own to be loaded to start and does not
|
||||
compete for resources other than what the application it is running will use.
|
||||
VMs on the other hand are pretty resource intensive on our processors, disks and
|
||||
memory hence running multiple VMs for various applications becomes a challenge
|
||||
in a limited capacity architecture.
|
||||
|
||||
<pre>
|
||||
┌────────────────────────┐ ┌───────────────────────┐
|
||||
│ ┌───────────┐ │ │ ┌───────────┐ │
|
||||
│ │ App │ │ │ │ App │ │
|
||||
│ └───────────┘ │ │ └───────────┘ │
|
||||
│ ┌────────┐ ┌────────┐ │ │ ┌────────┐ ┌───────┐ │
|
||||
│ │ Libs │ │ Deps │ │ │ │ Libs │ │ Deps │ │
|
||||
│ └────────┘ └────────┘ │ │ └────────┘ └───────┘ │
|
||||
│ ┌───────────────────┐ │ │ ┌──────────────────┐ │
|
||||
│ │ Guest OS │ │ │ │ Guest OS │ │
|
||||
│ └───────────────────┘ │ │ └──────────────────┘ │
|
||||
│ VM1 │ │ VM2 │
|
||||
└────────────────────────┘ └───────────────────────┘
|
||||
┌──────────────────────────────────────────────────┐
|
||||
│ Hypervisor │
|
||||
└──────────────────────────────────────────────────┘
|
||||
┌──────────────────────────────────────────────────┐
|
||||
│ Host OS │
|
||||
└──────────────────────────────────────────────────┘
|
||||
┌──────────────────────────────────────────────────┐
|
||||
│ Hardware Infrastructure │
|
||||
└──────────────────────────────────────────────────┘
|
||||
(VM based architecture)
|
||||
|
||||
┌────────────────────────┐ ┌───────────────────────┐
|
||||
│ ┌───────────┐ │ │ ┌───────────┐ │
|
||||
│ │ App │ │ │ │ App │ │
|
||||
│ └───────────┘ │ │ └───────────┘ │
|
||||
│ ┌────────┐ ┌────────┐ │ │ ┌────────┐ ┌───────┐ │
|
||||
│ │ Libs │ │ Deps │ │ │ │ Libs │ │ Deps │ │
|
||||
│ └────────┘ └────────┘ │ │ └────────┘ └───────┘ │
|
||||
│ Container1 │ │ Container2 │
|
||||
└────────────────────────┘ └───────────────────────┘
|
||||
┌──────────────────────────────────────────────────┐
|
||||
│ Docker │
|
||||
└──────────────────────────────────────────────────┘
|
||||
┌──────────────────────────────────────────────────┐
|
||||
│ OS │
|
||||
└──────────────────────────────────────────────────┘
|
||||
┌──────────────────────────────────────────────────┐
|
||||
│ Hardware Infrastructure │
|
||||
└──────────────────────────────────────────────────┘
|
||||
(Docker based architecture)
|
||||
|
||||
</pre>
|
||||
|
||||
Couple of terms we will encounter frequently are Docker Images and Docker
|
||||
Containers. Images are packages or templates of containers all stored in a
|
||||
container registry such as [Docker Hub](https://hub.docker.com/). Containers
|
||||
are standalone, executable instances of these images which include code,
|
||||
runtime, system tools, system libraries and settings - everything required to
|
||||
get the software up and running. Coming to Docker, it follows a client-server
|
||||
architecture wherein the CLI client communicates with the server component,
|
||||
which here is, the Docker Engine using RESTful API to issue commands.
|
||||
|
||||
## The Docker CLI
|
||||
```bash
|
||||
# after installing Docker from https://docs.docker.com/get-docker/
|
||||
# To list available commands, either run `docker` with no parameters or execute
|
||||
# `docker help`
|
||||
$ docker
|
||||
|
||||
>>> docker [OPTIONS] COMMAND [ARG...]
|
||||
docker [ --help | -v | --version ]
|
||||
|
||||
A self-sufficient runtime for containers.
|
||||
|
||||
Options:
|
||||
--config string Location of client config files (default "/root/.docker")
|
||||
-c, --context string Name of the context to use to connect to the daemon (overrides DOCKER_HOST env var and default context set with "docker context use")
|
||||
-D, --debug Enable debug mode
|
||||
--help Print usage
|
||||
-H, --host value Daemon socket(s) to connect to (default [])
|
||||
-l, --log-level string Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info")
|
||||
--tls Use TLS; implied by --tlsverify
|
||||
--tlscacert string Trust certs signed only by this CA (default "/root/.docker/ca.pem")
|
||||
--tlscert string Path to TLS certificate file (default "/root/.docker/cert.pem")
|
||||
--tlskey string Path to TLS key file (default "/root/.docker/key.pem")
|
||||
--tlsverify Use TLS and verify the remote
|
||||
-v, --version Print version information and quit
|
||||
|
||||
Commands:
|
||||
attach Attach to a running container
|
||||
# […]
|
||||
|
||||
$ docker run hello-world
|
||||
# `docker run <container-name>` is used to run a container, it will pull the
|
||||
# images from Docker Hub if they don't already exist in your system. Here the
|
||||
# docker client connects to the daemon which in turn pulls the "hello-world"
|
||||
# image from the Docker Hub. The daemon then builds a new container from the
|
||||
# image which runs the executable that produces the output streamed back to the
|
||||
# client that we see on our terminals.
|
||||
|
||||
$ docker run -d ubuntu sleep 60s
|
||||
# The -d (or --detach) flag is when we want to run a container in the background
|
||||
# and return back to the terminal. Here we detach an ubuntu container from the
|
||||
# terminal, the output should be the id and the command exits. If we check
|
||||
# running containers, we should still see ours there:
|
||||
# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
# 133261b4894a ubuntu "sleep 60s" 3 seconds ago Up 2 seconds vigorous_gould
|
||||
|
||||
$ docker run <container-id> -p 3000:8000
|
||||
# The -p (or --publish) flag is used to expose port 8000 inside the container to
|
||||
# port 3000 outside the container. This is because the app inside the container
|
||||
# runs in isolation, hence the port 8000 where the app runs is private to the
|
||||
# container.
|
||||
|
||||
$ docker run -i
|
||||
# or
|
||||
$ docker run -it
|
||||
# Docker runs our containers in a non-interactive mode i.e. they do not accept
|
||||
# inputs or work dynamically while running. The -i flag keeps input open to the
|
||||
# container, and the -t flag creates a pseudo-terminal that the shell can attach
|
||||
# to (can be combined as -it)
|
||||
|
||||
$ docker ps -a
|
||||
# The `docker ps` command only shows running containers by default. To see all
|
||||
# containers, use the -a (or --all) flag
|
||||
# Running the above command should output something similar in the terminal:
|
||||
# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
# 82f84bf6912b hello-world "/hello" 9 minutes ago Exited (0) 9 minutes ago eloquent_sammet
|
||||
|
||||
|
||||
$ docker stop hello-world
|
||||
# or
|
||||
$ docker start hello-world
|
||||
# The stop command simply stops one or more containers, and the start command
|
||||
# starts the container(s) up again! `docker start -a ubuntu` will attach our
|
||||
# detached container back to the terminal i.e. runs in the foreground
|
||||
|
||||
$ docker create alpine
|
||||
# `docker create` creates a new container for us with the image specified (here,
|
||||
# alpine), the container does not auto-start unlike `docker run`. This command
|
||||
# is used to set up a container configuration and then `docker start` to shoot
|
||||
# it up when required. Note that the status is "Created":
|
||||
# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
# 4c71c727c73d alpine "/bin/sh" 29 seconds ago Created naughty_ritchie
|
||||
|
||||
$ docker rm 82f84
|
||||
# Removes one or more containers using their container ID.
|
||||
# P.S.: we can use only the first few characters of the entire ID to identify
|
||||
# containers
|
||||
|
||||
$ docker images
|
||||
# Displays all images and their information, created here means the latest image
|
||||
# tag updated on Docker Hub:
|
||||
# REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
# ubuntu latest a8780b506fa4 9 days ago 77.8MB
|
||||
# alpine latest 9c6f07244728 3 months ago 5.54MB
|
||||
# hello-world latest feb5d9fea6a5 13 months ago 13.3kB
|
||||
|
||||
$ docker rmi
|
||||
# Removes one or more images from your system which do not have their instances
|
||||
# (or containers as we know them) running. If the image has an attached
|
||||
# container, either delete the container first or use the -f (or --force) flag
|
||||
# to forcefully delete both the container and image.
|
||||
|
||||
$ docker pull busybox
|
||||
# The pull command downloads the specified image on our system from Docker Hub.
|
||||
|
||||
$ docker exec -it 7b272 bash
|
||||
# This command is used to run a command in the running container's default
|
||||
# directory. Here 7b272 was our ubuntu container and the above command would
|
||||
# help us interact with the container by opening a bash session.
|
||||
|
||||
$ docker logs <container-id>
|
||||
# Displays the information logged by the specified container
|
||||
# root@7b27222e4bb7:/# whoami
|
||||
# root
|
||||
# root@7b27222e4bb7:/# pwd
|
||||
# /
|
||||
# root@7b27222e4bb7:/# ls
|
||||
# bin boot dev etc home lib lib32 lib64 libx3 srv sys tmp usr var
|
||||
# root@7b27222e4bb7:/# exit
|
||||
# exit
|
||||
|
||||
# More commands can be found at https://docs.docker.com/engine/reference/commandline/docker/
|
||||
```
|
||||
## The Dockerfile
|
||||
The Dockerfile is a blueprint of a Docker image. We can mention the artifacts
|
||||
from our application along with their configurations into this file in the
|
||||
specific syntax to let anyone create a Docker image of our application.
|
||||
|
||||
### A few things to keep in mind:
|
||||
* It is always strictly named `Dockerfile` without any extensions
|
||||
* We have to build our custom image on top of some already available Docker base
|
||||
image. (there is an empty image called `scratch` which literally lets you build
|
||||
an image from scratch)
|
||||
* All capitalised commands are part of the syntax, they are not case-sensitive
|
||||
but used like a convention
|
||||
* Below is a sample Dockerfile but you can read in depth from the [official docs](https://docs.docker.com/engine/reference/builder/).
|
||||
|
||||
```Dockerfile
|
||||
FROM <base-image>
|
||||
# define base image
|
||||
|
||||
ENV USERNAME='admin'\
|
||||
PWD='****'
|
||||
# optionally define environmental variables
|
||||
|
||||
RUN apt-get update
|
||||
# run linux commands inside container env, does not affect host env
|
||||
# This executes during the time of image creation
|
||||
|
||||
COPY <src> <target>
|
||||
# executes on the host, copies files from src (usually on the host) to target
|
||||
# on the container
|
||||
|
||||
ENTRYPOINT ["some-script.sh"]
|
||||
# executes an entire script as an entrypoint
|
||||
|
||||
CMD [<args>,...]
|
||||
# always part of dockerfile, introduces entry point linux command e.g.
|
||||
# `CMD node server.js`
|
||||
# This executes after image creation only when the container from the image
|
||||
# is running.
|
||||
```
|
||||
### Build your images
|
||||
Use the `docker build` command after wrapping your application into a Docker
|
||||
image to run ( or build) it.
|
||||
|
||||
```bash
|
||||
|
||||
$ docker build <path-to-dockerfile>
|
||||
# used to build an image from the specified Dockerfile
|
||||
# instead of path we could also specify a URL
|
||||
# -t tag is optional and used to name and tag your images for e.g.
|
||||
# `$ docker build -t my-image:0.1 ./home/app`
|
||||
# rebuild images everytime you make changes in the dockerfile
|
||||
```
|
||||
|
||||
## Push your image to DockerHub
|
||||
If you want your application's Docker image to be made publicly available for
|
||||
any Docker user, you might wanna push it to the [Docker Hub](https://hub.docker.com/) which is a
|
||||
registry of Docker images. Make sure you have an account with a username and
|
||||
password on Docker Hub.
|
||||
|
||||
When pushing an image to Docker Hub, we must specify our Docker Hub username
|
||||
as part of the source image name. We need to create the target image with the
|
||||
tag name of username/image-name much like GitHub repositories.
|
||||
|
||||
```bash
|
||||
$ docker login
|
||||
# to login to Docker Hub using your username and password
|
||||
|
||||
$ docker tag <src-image>[:<src-tag>] <target-image>[:<target-tag>]
|
||||
# this tags a local src-image to a public target-image
|
||||
# e.g. `docker tag my-sample-app:1.0.0 akshitadixit/my-sample-app`
|
||||
# if tags are not specified, they're defaulted to `latest`
|
||||
|
||||
$ docker push <target-image>[:<target-tag>]
|
||||
# uploads our image to Docker Hub
|
||||
# e.g. `docker push akshitadixit/my-sample-app`
|
||||
# this image will be accessible under your profile's repositories as
|
||||
# `https://hub.docker.com/r/username/image-name`
|
||||
|
||||
```
|
||||
|
@ -1,167 +1,167 @@
|
||||
---
|
||||
language: docker
|
||||
filename: docker-es.bat
|
||||
contributors:
|
||||
- ["Ruslan López", "http://javapro.org/"]
|
||||
- ["Michael Chen", "https://github.com/ML-Chen"]
|
||||
lang: es-es
|
||||
---
|
||||
|
||||
```bat
|
||||
:: descargar, instalar y ejecutar la imágen del hola mundo
|
||||
docker run hello-world
|
||||
|
||||
:: Si esta es la primera vez, deberíais de poder ver el mensaje
|
||||
:: Unable to find image 'hello-world:latest' locally
|
||||
:: latest: Pulling from library/hello-world
|
||||
:: 1b930d010525: Pull complete
|
||||
:: Digest: sha256:4fe721ccc2e8dc7362278a29dc660d833570ec2682f4e4194f4ee23e415e1064
|
||||
:: Status: Downloaded newer image for hello-world:latest
|
||||
::
|
||||
:: Hello from Docker!
|
||||
:: This message shows that your installation appears to be working correctly.
|
||||
::
|
||||
:: To generate this message, Docker took the following steps:
|
||||
:: 1. The Docker client contacted the Docker daemon.
|
||||
:: 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
|
||||
:: (amd64)
|
||||
:: 3. The Docker daemon created a new container from that image which runs the
|
||||
:: executable that produces the output you are currently reading.
|
||||
:: 4. The Docker daemon streamed that output to the Docker client, which sent it
|
||||
:: to your terminal.
|
||||
::
|
||||
:: To try something more ambitious, you can run an Ubuntu container with:
|
||||
:: $ docker run -it ubuntu bash
|
||||
::
|
||||
:: Share images, automate workflows, and more with a free Docker ID:
|
||||
:: https://hub.docker.com/
|
||||
::
|
||||
:: For more examples and ideas, visit:
|
||||
:: https://docs.docker.com/get-started/
|
||||
:: El susodicho mensaje se podría traducir como:
|
||||
::
|
||||
:: Hola desde Docker!
|
||||
:: Este mensaje muestra que su instalación parece estar funcionando crrectamente.
|
||||
::
|
||||
:: Para generar este mensaje, Docker realizó los siguientes pasos:
|
||||
:: 1. El cliente de Docker contactó a Docker daemon.
|
||||
:: 2. El Docker daemon obtubo la imágen "hello-world" desde Docker Hub.
|
||||
:: (amd64)
|
||||
:: 3. El Docker daemon creó un nuevo contenedor a partir de esa imagen con la cual ejecuta el
|
||||
:: ejecutable que produce la salida que estás leyendo.
|
||||
:: 4. El Docker daemon transmitió dicha salida el cliente Docker, el cual
|
||||
:: la envió a tu terminal.
|
||||
::
|
||||
:: Para intentar algo más ambicioso, puede correr un contenedor Ubuntu mediante:
|
||||
:: $ docker run -it ubuntu bash
|
||||
::
|
||||
:: Comparte imágenes, automatice flujos y más con un Docker ID gratuito:
|
||||
:: https://hub.docker.com/
|
||||
|
||||
:: ahora veamos las imágenes que se están ejecutando actualmente
|
||||
docker ps
|
||||
:: CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
|
||||
:: NAMES
|
||||
|
||||
:: veamos las imágenes que hemos ejecutado previamente
|
||||
docker ps -a
|
||||
|
||||
:: CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
|
||||
:: NAMES
|
||||
:: 4a76281f9c53 hello-world "/hello" 2 minutes ago Exited (0) 2 minutes ago
|
||||
:: happy_poincare
|
||||
:: la parte del nombre se genera automáticamente, así que probablemente sea diferente para vos
|
||||
|
||||
:: eliminemos nuestra imagen previamente generada
|
||||
docker rm happy_poincare
|
||||
|
||||
:: verifiquemos si realmente fue borrada
|
||||
docker ps -a
|
||||
:: CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
|
||||
:: NAMES
|
||||
|
||||
:: especifiquemos un nombre personalizado para el contenedor
|
||||
docker run --name test_container hello-world
|
||||
:: Hello from Docker!
|
||||
:: This message shows that your installation appears to be working correctly.
|
||||
::
|
||||
:: To generate this message, Docker took the following steps:
|
||||
:: 1. The Docker client contacted the Docker daemon.
|
||||
:: 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
|
||||
:: (amd64)
|
||||
:: 3. The Docker daemon created a new container from that image which runs the
|
||||
:: executable that produces the output you are currently reading.
|
||||
:: 4. The Docker daemon streamed that output to the Docker client, which sent it
|
||||
:: to your terminal.
|
||||
::
|
||||
:: To try something more ambitious, you can run an Ubuntu container with:
|
||||
:: $ docker run -it ubuntu bash
|
||||
::
|
||||
:: Share images, automate workflows, and more with a free Docker ID:
|
||||
:: https://hub.docker.com/
|
||||
::
|
||||
:: For more examples and ideas, visit:
|
||||
:: https://docs.docker.com/get-started/
|
||||
|
||||
docker ps -a
|
||||
:: CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
|
||||
:: NAMES
|
||||
:: d345fe1a4f41 hello-world "/hello" About a minute ago Exited (0) About a minute ago
|
||||
:: test_container
|
||||
:: tal como podeis ver el nombre es el que especificamos
|
||||
|
||||
:: obtener los registros de un contenedor nombrado
|
||||
docker logs test_container
|
||||
:: Hello from Docker!
|
||||
:: This message shows that your installation appears to be working correctly.
|
||||
::
|
||||
:: To generate this message, Docker took the following steps:
|
||||
:: 1. The Docker client contacted the Docker daemon.
|
||||
:: 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
|
||||
:: (amd64)
|
||||
:: 3. The Docker daemon created a new container from that image which runs the
|
||||
:: executable that produces the output you are currently reading.
|
||||
:: 4. The Docker daemon streamed that output to the Docker client, which sent it
|
||||
:: to your terminal.
|
||||
::
|
||||
:: To try something more ambitious, you can run an Ubuntu container with:
|
||||
:: $ docker run -it ubuntu bash
|
||||
::
|
||||
:: Share images, automate workflows, and more with a free Docker ID:
|
||||
:: https://hub.docker.com/
|
||||
::
|
||||
:: For more examples and ideas, visit:
|
||||
:: https://docs.docker.com/get-started/
|
||||
|
||||
docker rm test_container
|
||||
|
||||
docker run ubuntu
|
||||
:: Unable to find image 'ubuntu:latest' locally
|
||||
:: latest: Pulling from library/ubuntu
|
||||
:: 2746a4a261c9: Pull complete
|
||||
:: 4c1d20cdee96: Pull complete 0d3160e1d0de: Pull complete c8e37668deea: Pull complete Digest: sha256:250cc6f3f3ffc5cdaa9d8f4946ac79821aafb4d3afc93928f0de9336eba21aa4
|
||||
:: Status: Downloaded newer image for ubuntu:latest
|
||||
|
||||
docker ps -a
|
||||
:: CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
|
||||
:: NAMES
|
||||
:: c19e9e5b000a ubuntu "/bin/bash" 5 seconds ago Exited (0) 4 seconds ago
|
||||
:: relaxed_nobel
|
||||
|
||||
:: ejecutando un contenedor en modo interactivo
|
||||
docker run -it ubuntu
|
||||
:: root@e2cac48323d2:/# uname
|
||||
:: Linux
|
||||
:: root@e2cac48323d2:/# exit
|
||||
:: exit
|
||||
|
||||
docker rm relaxed_nobel
|
||||
|
||||
docker ps -a
|
||||
:: CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
|
||||
:: NAMES
|
||||
:: e2cac48323d2 ubuntu "/bin/bash" 2 minutes ago Exited (0) About a minute ago
|
||||
:: nifty_goldwasser
|
||||
|
||||
docker rm nifty_goldwasser
|
||||
```
|
||||
---
|
||||
language: docker
|
||||
filename: docker-es.bat
|
||||
contributors:
|
||||
- ["Ruslan López", "http://javapro.org/"]
|
||||
- ["Michael Chen", "https://github.com/ML-Chen"]
|
||||
lang: es-es
|
||||
---
|
||||
|
||||
```bat
|
||||
:: descargar, instalar y ejecutar la imágen del hola mundo
|
||||
docker run hello-world
|
||||
|
||||
:: Si esta es la primera vez, deberíais de poder ver el mensaje
|
||||
:: Unable to find image 'hello-world:latest' locally
|
||||
:: latest: Pulling from library/hello-world
|
||||
:: 1b930d010525: Pull complete
|
||||
:: Digest: sha256:4fe721ccc2e8dc7362278a29dc660d833570ec2682f4e4194f4ee23e415e1064
|
||||
:: Status: Downloaded newer image for hello-world:latest
|
||||
::
|
||||
:: Hello from Docker!
|
||||
:: This message shows that your installation appears to be working correctly.
|
||||
::
|
||||
:: To generate this message, Docker took the following steps:
|
||||
:: 1. The Docker client contacted the Docker daemon.
|
||||
:: 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
|
||||
:: (amd64)
|
||||
:: 3. The Docker daemon created a new container from that image which runs the
|
||||
:: executable that produces the output you are currently reading.
|
||||
:: 4. The Docker daemon streamed that output to the Docker client, which sent it
|
||||
:: to your terminal.
|
||||
::
|
||||
:: To try something more ambitious, you can run an Ubuntu container with:
|
||||
:: $ docker run -it ubuntu bash
|
||||
::
|
||||
:: Share images, automate workflows, and more with a free Docker ID:
|
||||
:: https://hub.docker.com/
|
||||
::
|
||||
:: For more examples and ideas, visit:
|
||||
:: https://docs.docker.com/get-started/
|
||||
:: El susodicho mensaje se podría traducir como:
|
||||
::
|
||||
:: Hola desde Docker!
|
||||
:: Este mensaje muestra que su instalación parece estar funcionando crrectamente.
|
||||
::
|
||||
:: Para generar este mensaje, Docker realizó los siguientes pasos:
|
||||
:: 1. El cliente de Docker contactó a Docker daemon.
|
||||
:: 2. El Docker daemon obtubo la imágen "hello-world" desde Docker Hub.
|
||||
:: (amd64)
|
||||
:: 3. El Docker daemon creó un nuevo contenedor a partir de esa imagen con la cual ejecuta el
|
||||
:: ejecutable que produce la salida que estás leyendo.
|
||||
:: 4. El Docker daemon transmitió dicha salida el cliente Docker, el cual
|
||||
:: la envió a tu terminal.
|
||||
::
|
||||
:: Para intentar algo más ambicioso, puede correr un contenedor Ubuntu mediante:
|
||||
:: $ docker run -it ubuntu bash
|
||||
::
|
||||
:: Comparte imágenes, automatice flujos y más con un Docker ID gratuito:
|
||||
:: https://hub.docker.com/
|
||||
|
||||
:: ahora veamos las imágenes que se están ejecutando actualmente
|
||||
docker ps
|
||||
:: CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
|
||||
:: NAMES
|
||||
|
||||
:: veamos las imágenes que hemos ejecutado previamente
|
||||
docker ps -a
|
||||
|
||||
:: CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
|
||||
:: NAMES
|
||||
:: 4a76281f9c53 hello-world "/hello" 2 minutes ago Exited (0) 2 minutes ago
|
||||
:: happy_poincare
|
||||
:: la parte del nombre se genera automáticamente, así que probablemente sea diferente para vos
|
||||
|
||||
:: eliminemos nuestra imagen previamente generada
|
||||
docker rm happy_poincare
|
||||
|
||||
:: verifiquemos si realmente fue borrada
|
||||
docker ps -a
|
||||
:: CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
|
||||
:: NAMES
|
||||
|
||||
:: especifiquemos un nombre personalizado para el contenedor
|
||||
docker run --name test_container hello-world
|
||||
:: Hello from Docker!
|
||||
:: This message shows that your installation appears to be working correctly.
|
||||
::
|
||||
:: To generate this message, Docker took the following steps:
|
||||
:: 1. The Docker client contacted the Docker daemon.
|
||||
:: 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
|
||||
:: (amd64)
|
||||
:: 3. The Docker daemon created a new container from that image which runs the
|
||||
:: executable that produces the output you are currently reading.
|
||||
:: 4. The Docker daemon streamed that output to the Docker client, which sent it
|
||||
:: to your terminal.
|
||||
::
|
||||
:: To try something more ambitious, you can run an Ubuntu container with:
|
||||
:: $ docker run -it ubuntu bash
|
||||
::
|
||||
:: Share images, automate workflows, and more with a free Docker ID:
|
||||
:: https://hub.docker.com/
|
||||
::
|
||||
:: For more examples and ideas, visit:
|
||||
:: https://docs.docker.com/get-started/
|
||||
|
||||
docker ps -a
|
||||
:: CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
|
||||
:: NAMES
|
||||
:: d345fe1a4f41 hello-world "/hello" About a minute ago Exited (0) About a minute ago
|
||||
:: test_container
|
||||
:: tal como podeis ver el nombre es el que especificamos
|
||||
|
||||
:: obtener los registros de un contenedor nombrado
|
||||
docker logs test_container
|
||||
:: Hello from Docker!
|
||||
:: This message shows that your installation appears to be working correctly.
|
||||
::
|
||||
:: To generate this message, Docker took the following steps:
|
||||
:: 1. The Docker client contacted the Docker daemon.
|
||||
:: 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
|
||||
:: (amd64)
|
||||
:: 3. The Docker daemon created a new container from that image which runs the
|
||||
:: executable that produces the output you are currently reading.
|
||||
:: 4. The Docker daemon streamed that output to the Docker client, which sent it
|
||||
:: to your terminal.
|
||||
::
|
||||
:: To try something more ambitious, you can run an Ubuntu container with:
|
||||
:: $ docker run -it ubuntu bash
|
||||
::
|
||||
:: Share images, automate workflows, and more with a free Docker ID:
|
||||
:: https://hub.docker.com/
|
||||
::
|
||||
:: For more examples and ideas, visit:
|
||||
:: https://docs.docker.com/get-started/
|
||||
|
||||
docker rm test_container
|
||||
|
||||
docker run ubuntu
|
||||
:: Unable to find image 'ubuntu:latest' locally
|
||||
:: latest: Pulling from library/ubuntu
|
||||
:: 2746a4a261c9: Pull complete
|
||||
:: 4c1d20cdee96: Pull complete 0d3160e1d0de: Pull complete c8e37668deea: Pull complete Digest: sha256:250cc6f3f3ffc5cdaa9d8f4946ac79821aafb4d3afc93928f0de9336eba21aa4
|
||||
:: Status: Downloaded newer image for ubuntu:latest
|
||||
|
||||
docker ps -a
|
||||
:: CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
|
||||
:: NAMES
|
||||
:: c19e9e5b000a ubuntu "/bin/bash" 5 seconds ago Exited (0) 4 seconds ago
|
||||
:: relaxed_nobel
|
||||
|
||||
:: ejecutando un contenedor en modo interactivo
|
||||
docker run -it ubuntu
|
||||
:: root@e2cac48323d2:/# uname
|
||||
:: Linux
|
||||
:: root@e2cac48323d2:/# exit
|
||||
:: exit
|
||||
|
||||
docker rm relaxed_nobel
|
||||
|
||||
docker ps -a
|
||||
:: CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
|
||||
:: NAMES
|
||||
:: e2cac48323d2 ubuntu "/bin/bash" 2 minutes ago Exited (0) About a minute ago
|
||||
:: nifty_goldwasser
|
||||
|
||||
docker rm nifty_goldwasser
|
||||
```
|
||||
|
@ -1,276 +1,276 @@
|
||||
---
|
||||
language: toml
|
||||
filename: learntoml-it.toml
|
||||
contributors:
|
||||
- ["Alois de Gouvello", "https://github.com/aloisdg"]
|
||||
translators:
|
||||
- ["Christian Grasso", "https://grasso.io"]
|
||||
lang: it-it
|
||||
---
|
||||
|
||||
TOML è l'acronimo di _Tom's Obvious, Minimal Language_. È un linguaggio per la
|
||||
serializzazione di dati, progettato per i file di configurazione.
|
||||
|
||||
È un'alternativa a linguaggi come YAML e JSON, che punta ad essere più leggibile
|
||||
per le persone. Allo stesso tempo, TOML può essere utilizzato in modo abbastanza
|
||||
semplice nella maggior parte dei linguaggi di programmazione, in quanto è
|
||||
progettato per essere tradotto senza ambiguità in una hash table.
|
||||
|
||||
Tieni presente che TOML è ancora in fase di sviluppo, e la sua specifica non è
|
||||
ancora stabile. Questo documento utilizza TOML 0.4.0.
|
||||
|
||||
```toml
|
||||
# I commenti in TOML sono fatti così.
|
||||
|
||||
################
|
||||
# TIPI SCALARI #
|
||||
################
|
||||
|
||||
# Il nostro oggetto root (corrispondente all'intero documento) sarà una mappa,
|
||||
# anche chiamata dizionario, hash o oggetto in altri linguaggi.
|
||||
|
||||
# La key, il simbolo di uguale e il valore devono trovarsi sulla stessa riga,
|
||||
# eccetto per alcuni tipi di valori.
|
||||
key = "value"
|
||||
stringa = "ciao"
|
||||
numero = 42
|
||||
float = 3.14
|
||||
boolean = true
|
||||
data = 1979-05-27T07:32:00-08:00
|
||||
notazScientifica = 1e+12
|
||||
"puoi utilizzare le virgolette per la key" = true # Puoi usare " oppure '
|
||||
"la key può contenere" = "lettere, numeri, underscore e trattini"
|
||||
|
||||
############
|
||||
# Stringhe #
|
||||
############
|
||||
|
||||
# Le stringhe possono contenere solo caratteri UTF-8 validi.
|
||||
# Possiamo effettuare l'escape dei caratteri, e alcuni hanno delle sequenze
|
||||
# di escape compatte. Ad esempio, \t corrisponde al TAB.
|
||||
stringaSemplice = "Racchiusa tra virgolette. \"Usa il backslash per l'escape\"."
|
||||
|
||||
stringaMultiriga = """
|
||||
Racchiusa da tre virgolette doppie all'inizio e
|
||||
alla fine - consente di andare a capo."""
|
||||
|
||||
stringaLiteral = 'Virgolette singole. Non consente di effettuare escape.'
|
||||
|
||||
stringaMultirigaLiteral = '''
|
||||
Racchiusa da tre virgolette singole all'inizio e
|
||||
alla fine - consente di andare a capo.
|
||||
Anche in questo caso non si può fare escape.
|
||||
Il primo ritorno a capo viene eliminato.
|
||||
Tutti gli altri spazi aggiuntivi
|
||||
vengono mantenuti.
|
||||
'''
|
||||
|
||||
# Per i dati binari è consigliabile utilizzare Base64 e
|
||||
# gestirli manualmente dall'applicazione.
|
||||
|
||||
##########
|
||||
# Interi #
|
||||
##########
|
||||
|
||||
## Gli interi possono avere o meno un segno (+, -).
|
||||
## Non si possono inserire zero superflui all'inizio.
|
||||
## Non è possibile inoltre utilizzare valori numerici
|
||||
## non rappresentabili con una sequenza di cifre.
|
||||
int1 = +42
|
||||
int2 = 0
|
||||
int3 = -21
|
||||
|
||||
## Puoi utilizzare gli underscore per migliorare la leggibilità.
|
||||
## Fai attenzione a non inserirne due di seguito.
|
||||
int4 = 5_349_221
|
||||
int5 = 1_2_3_4_5 # VALIDO, ma da evitare
|
||||
|
||||
#########
|
||||
# Float #
|
||||
#########
|
||||
|
||||
# I float permettono di rappresentare numeri decimali.
|
||||
flt1 = 3.1415
|
||||
flt2 = -5e6
|
||||
flt3 = 6.626E-34
|
||||
|
||||
###########
|
||||
# Boolean #
|
||||
###########
|
||||
|
||||
# I valori boolean (true/false) devono essere scritti in minuscolo.
|
||||
bool1 = true
|
||||
bool2 = false
|
||||
|
||||
############
|
||||
# Data/ora #
|
||||
############
|
||||
|
||||
data1 = 1979-05-27T07:32:00Z # Specifica RFC 3339/ISO 8601 (UTC)
|
||||
data2 = 1979-05-26T15:32:00+08:00 # RFC 3339/ISO 8601 con offset
|
||||
|
||||
######################
|
||||
# TIPI DI COLLECTION #
|
||||
######################
|
||||
|
||||
#########
|
||||
# Array #
|
||||
#########
|
||||
|
||||
array1 = [ 1, 2, 3 ]
|
||||
array2 = [ "Le", "virgole", "sono", "delimitatori" ]
|
||||
array3 = [ "Non", "unire", "tipi", "diversi" ]
|
||||
array4 = [ "tutte", 'le stringhe', """hanno lo stesso""", '''tipo''' ]
|
||||
array5 = [
|
||||
"Gli spazi vuoti", "sono", "ignorati"
|
||||
]
|
||||
|
||||
###########
|
||||
# Tabelle #
|
||||
###########
|
||||
|
||||
# Le tabelle (o hash table o dizionari) sono collection di coppie key/value.
|
||||
# Iniziano con un nome tra parentesi quadre su una linea separata.
|
||||
# Le tabelle vuote (senza alcun valore) sono valide.
|
||||
[tabella]
|
||||
|
||||
# Tutti i valori che si trovano sotto il nome della tabella
|
||||
# appartengono alla tabella stessa (finchè non ne viene creata un'altra).
|
||||
# L'ordine di questi valori non è garantito.
|
||||
[tabella-1]
|
||||
key1 = "una stringa"
|
||||
key2 = 123
|
||||
|
||||
[tabella-2]
|
||||
key1 = "un'altra stringa"
|
||||
key2 = 456
|
||||
|
||||
# Utilizzando i punti è possibile creare delle sottotabelle.
|
||||
# Ogni parte suddivisa dai punti segue le regole delle key per il nome.
|
||||
[tabella-3."sotto.tabella"]
|
||||
key1 = "prova"
|
||||
|
||||
# Ecco l'equivalente JSON della tabella precedente:
|
||||
# { "tabella-3": { "sotto.tabella": { "key1": "prova" } } }
|
||||
|
||||
# Gli spazi non vengono considerati, ma è consigliabile
|
||||
# evitare di usare spazi superflui.
|
||||
[a.b.c] # consigliato
|
||||
[ d.e.f ] # identico a [d.e.f]
|
||||
|
||||
# Non c'è bisogno di creare le tabelle superiori per creare una sottotabella.
|
||||
# [x] queste
|
||||
# [x.y] non
|
||||
# [x.y.z] servono
|
||||
[x.y.z.w] # per creare questa tabella
|
||||
|
||||
# Se non è stata già creata prima, puoi anche creare
|
||||
# una tabella superiore più avanti.
|
||||
[a.b]
|
||||
c = 1
|
||||
|
||||
[a]
|
||||
d = 2
|
||||
|
||||
# Non puoi definire una key o una tabella più di una volta.
|
||||
|
||||
# ERRORE
|
||||
[a]
|
||||
b = 1
|
||||
|
||||
[a]
|
||||
c = 2
|
||||
|
||||
# ERRORE
|
||||
[a]
|
||||
b = 1
|
||||
|
||||
[a.b]
|
||||
c = 2
|
||||
|
||||
# I nomi delle tabelle non possono essere vuoti.
|
||||
[] # NON VALIDO
|
||||
[a.] # NON VALIDO
|
||||
[a..b] # NON VALIDO
|
||||
[.b] # NON VALIDO
|
||||
[.] # NON VALIDO
|
||||
|
||||
##################
|
||||
# Tabelle inline #
|
||||
##################
|
||||
|
||||
tabelleInline = { racchiuseData = "{ e }", rigaSingola = true }
|
||||
punto = { x = 1, y = 2 }
|
||||
|
||||
####################
|
||||
# Array di tabelle #
|
||||
####################
|
||||
|
||||
# Un array di tabelle può essere creato utilizzando due parentesi quadre.
|
||||
# Tutte le tabelle con questo nome saranno elementi dell'array.
|
||||
# Gli elementi vengono inseriti nell'ordine in cui si trovano.
|
||||
|
||||
[[prodotti]]
|
||||
nome = "array di tabelle"
|
||||
sku = 738594937
|
||||
tabelleVuoteValide = true
|
||||
|
||||
[[prodotti]]
|
||||
|
||||
[[prodotti]]
|
||||
nome = "un altro item"
|
||||
sku = 284758393
|
||||
colore = "grigio"
|
||||
|
||||
# Puoi anche creare array di tabelle nested. Le sottotabelle con doppie
|
||||
# parentesi quadre apparterranno alla tabella più vicina sopra di esse.
|
||||
|
||||
[[frutta]]
|
||||
nome = "mela"
|
||||
|
||||
[frutto.geometria]
|
||||
forma = "sferica"
|
||||
nota = "Sono una proprietà del frutto"
|
||||
|
||||
[[frutto.colore]]
|
||||
nome = "rosso"
|
||||
nota = "Sono un oggetto di un array dentro mela"
|
||||
|
||||
[[frutto.colore]]
|
||||
nome = "verde"
|
||||
nota = "Sono nello stesso array di rosso"
|
||||
|
||||
[[frutta]]
|
||||
nome = "banana"
|
||||
|
||||
[[frutto.colore]]
|
||||
nome = "giallo"
|
||||
nota = "Anche io sono un oggetto di un array, ma dentro banana"
|
||||
```
|
||||
|
||||
Ecco l'equivalente JSON dell'ultima tabella:
|
||||
|
||||
```json
|
||||
{
|
||||
"frutta": [
|
||||
{
|
||||
"nome": "mela",
|
||||
"geometria": { "forma": "sferica", "nota": "..."},
|
||||
"colore": [
|
||||
{ "nome": "rosso", "nota": "..." },
|
||||
{ "nome": "verde", "nota": "..." }
|
||||
]
|
||||
},
|
||||
{
|
||||
"nome": "banana",
|
||||
"colore": [
|
||||
{ "nome": "giallo", "nota": "..." }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Altre risorse
|
||||
|
||||
+ [Repository ufficiale di TOML](https://github.com/toml-lang/toml)
|
||||
---
|
||||
language: toml
|
||||
filename: learntoml-it.toml
|
||||
contributors:
|
||||
- ["Alois de Gouvello", "https://github.com/aloisdg"]
|
||||
translators:
|
||||
- ["Christian Grasso", "https://grasso.io"]
|
||||
lang: it-it
|
||||
---
|
||||
|
||||
TOML è l'acronimo di _Tom's Obvious, Minimal Language_. È un linguaggio per la
|
||||
serializzazione di dati, progettato per i file di configurazione.
|
||||
|
||||
È un'alternativa a linguaggi come YAML e JSON, che punta ad essere più leggibile
|
||||
per le persone. Allo stesso tempo, TOML può essere utilizzato in modo abbastanza
|
||||
semplice nella maggior parte dei linguaggi di programmazione, in quanto è
|
||||
progettato per essere tradotto senza ambiguità in una hash table.
|
||||
|
||||
Tieni presente che TOML è ancora in fase di sviluppo, e la sua specifica non è
|
||||
ancora stabile. Questo documento utilizza TOML 0.4.0.
|
||||
|
||||
```toml
|
||||
# I commenti in TOML sono fatti così.
|
||||
|
||||
################
|
||||
# TIPI SCALARI #
|
||||
################
|
||||
|
||||
# Il nostro oggetto root (corrispondente all'intero documento) sarà una mappa,
|
||||
# anche chiamata dizionario, hash o oggetto in altri linguaggi.
|
||||
|
||||
# La key, il simbolo di uguale e il valore devono trovarsi sulla stessa riga,
|
||||
# eccetto per alcuni tipi di valori.
|
||||
key = "value"
|
||||
stringa = "ciao"
|
||||
numero = 42
|
||||
float = 3.14
|
||||
boolean = true
|
||||
data = 1979-05-27T07:32:00-08:00
|
||||
notazScientifica = 1e+12
|
||||
"puoi utilizzare le virgolette per la key" = true # Puoi usare " oppure '
|
||||
"la key può contenere" = "lettere, numeri, underscore e trattini"
|
||||
|
||||
############
|
||||
# Stringhe #
|
||||
############
|
||||
|
||||
# Le stringhe possono contenere solo caratteri UTF-8 validi.
|
||||
# Possiamo effettuare l'escape dei caratteri, e alcuni hanno delle sequenze
|
||||
# di escape compatte. Ad esempio, \t corrisponde al TAB.
|
||||
stringaSemplice = "Racchiusa tra virgolette. \"Usa il backslash per l'escape\"."
|
||||
|
||||
stringaMultiriga = """
|
||||
Racchiusa da tre virgolette doppie all'inizio e
|
||||
alla fine - consente di andare a capo."""
|
||||
|
||||
stringaLiteral = 'Virgolette singole. Non consente di effettuare escape.'
|
||||
|
||||
stringaMultirigaLiteral = '''
|
||||
Racchiusa da tre virgolette singole all'inizio e
|
||||
alla fine - consente di andare a capo.
|
||||
Anche in questo caso non si può fare escape.
|
||||
Il primo ritorno a capo viene eliminato.
|
||||
Tutti gli altri spazi aggiuntivi
|
||||
vengono mantenuti.
|
||||
'''
|
||||
|
||||
# Per i dati binari è consigliabile utilizzare Base64 e
|
||||
# gestirli manualmente dall'applicazione.
|
||||
|
||||
##########
|
||||
# Interi #
|
||||
##########
|
||||
|
||||
## Gli interi possono avere o meno un segno (+, -).
|
||||
## Non si possono inserire zero superflui all'inizio.
|
||||
## Non è possibile inoltre utilizzare valori numerici
|
||||
## non rappresentabili con una sequenza di cifre.
|
||||
int1 = +42
|
||||
int2 = 0
|
||||
int3 = -21
|
||||
|
||||
## Puoi utilizzare gli underscore per migliorare la leggibilità.
|
||||
## Fai attenzione a non inserirne due di seguito.
|
||||
int4 = 5_349_221
|
||||
int5 = 1_2_3_4_5 # VALIDO, ma da evitare
|
||||
|
||||
#########
|
||||
# Float #
|
||||
#########
|
||||
|
||||
# I float permettono di rappresentare numeri decimali.
|
||||
flt1 = 3.1415
|
||||
flt2 = -5e6
|
||||
flt3 = 6.626E-34
|
||||
|
||||
###########
|
||||
# Boolean #
|
||||
###########
|
||||
|
||||
# I valori boolean (true/false) devono essere scritti in minuscolo.
|
||||
bool1 = true
|
||||
bool2 = false
|
||||
|
||||
############
|
||||
# Data/ora #
|
||||
############
|
||||
|
||||
data1 = 1979-05-27T07:32:00Z # Specifica RFC 3339/ISO 8601 (UTC)
|
||||
data2 = 1979-05-26T15:32:00+08:00 # RFC 3339/ISO 8601 con offset
|
||||
|
||||
######################
|
||||
# TIPI DI COLLECTION #
|
||||
######################
|
||||
|
||||
#########
|
||||
# Array #
|
||||
#########
|
||||
|
||||
array1 = [ 1, 2, 3 ]
|
||||
array2 = [ "Le", "virgole", "sono", "delimitatori" ]
|
||||
array3 = [ "Non", "unire", "tipi", "diversi" ]
|
||||
array4 = [ "tutte", 'le stringhe', """hanno lo stesso""", '''tipo''' ]
|
||||
array5 = [
|
||||
"Gli spazi vuoti", "sono", "ignorati"
|
||||
]
|
||||
|
||||
###########
|
||||
# Tabelle #
|
||||
###########
|
||||
|
||||
# Le tabelle (o hash table o dizionari) sono collection di coppie key/value.
|
||||
# Iniziano con un nome tra parentesi quadre su una linea separata.
|
||||
# Le tabelle vuote (senza alcun valore) sono valide.
|
||||
[tabella]
|
||||
|
||||
# Tutti i valori che si trovano sotto il nome della tabella
|
||||
# appartengono alla tabella stessa (finchè non ne viene creata un'altra).
|
||||
# L'ordine di questi valori non è garantito.
|
||||
[tabella-1]
|
||||
key1 = "una stringa"
|
||||
key2 = 123
|
||||
|
||||
[tabella-2]
|
||||
key1 = "un'altra stringa"
|
||||
key2 = 456
|
||||
|
||||
# Utilizzando i punti è possibile creare delle sottotabelle.
|
||||
# Ogni parte suddivisa dai punti segue le regole delle key per il nome.
|
||||
[tabella-3."sotto.tabella"]
|
||||
key1 = "prova"
|
||||
|
||||
# Ecco l'equivalente JSON della tabella precedente:
|
||||
# { "tabella-3": { "sotto.tabella": { "key1": "prova" } } }
|
||||
|
||||
# Gli spazi non vengono considerati, ma è consigliabile
|
||||
# evitare di usare spazi superflui.
|
||||
[a.b.c] # consigliato
|
||||
[ d.e.f ] # identico a [d.e.f]
|
||||
|
||||
# Non c'è bisogno di creare le tabelle superiori per creare una sottotabella.
|
||||
# [x] queste
|
||||
# [x.y] non
|
||||
# [x.y.z] servono
|
||||
[x.y.z.w] # per creare questa tabella
|
||||
|
||||
# Se non è stata già creata prima, puoi anche creare
|
||||
# una tabella superiore più avanti.
|
||||
[a.b]
|
||||
c = 1
|
||||
|
||||
[a]
|
||||
d = 2
|
||||
|
||||
# Non puoi definire una key o una tabella più di una volta.
|
||||
|
||||
# ERRORE
|
||||
[a]
|
||||
b = 1
|
||||
|
||||
[a]
|
||||
c = 2
|
||||
|
||||
# ERRORE
|
||||
[a]
|
||||
b = 1
|
||||
|
||||
[a.b]
|
||||
c = 2
|
||||
|
||||
# I nomi delle tabelle non possono essere vuoti.
|
||||
[] # NON VALIDO
|
||||
[a.] # NON VALIDO
|
||||
[a..b] # NON VALIDO
|
||||
[.b] # NON VALIDO
|
||||
[.] # NON VALIDO
|
||||
|
||||
##################
|
||||
# Tabelle inline #
|
||||
##################
|
||||
|
||||
tabelleInline = { racchiuseData = "{ e }", rigaSingola = true }
|
||||
punto = { x = 1, y = 2 }
|
||||
|
||||
####################
|
||||
# Array di tabelle #
|
||||
####################
|
||||
|
||||
# Un array di tabelle può essere creato utilizzando due parentesi quadre.
|
||||
# Tutte le tabelle con questo nome saranno elementi dell'array.
|
||||
# Gli elementi vengono inseriti nell'ordine in cui si trovano.
|
||||
|
||||
[[prodotti]]
|
||||
nome = "array di tabelle"
|
||||
sku = 738594937
|
||||
tabelleVuoteValide = true
|
||||
|
||||
[[prodotti]]
|
||||
|
||||
[[prodotti]]
|
||||
nome = "un altro item"
|
||||
sku = 284758393
|
||||
colore = "grigio"
|
||||
|
||||
# Puoi anche creare array di tabelle nested. Le sottotabelle con doppie
|
||||
# parentesi quadre apparterranno alla tabella più vicina sopra di esse.
|
||||
|
||||
[[frutta]]
|
||||
nome = "mela"
|
||||
|
||||
[frutto.geometria]
|
||||
forma = "sferica"
|
||||
nota = "Sono una proprietà del frutto"
|
||||
|
||||
[[frutto.colore]]
|
||||
nome = "rosso"
|
||||
nota = "Sono un oggetto di un array dentro mela"
|
||||
|
||||
[[frutto.colore]]
|
||||
nome = "verde"
|
||||
nota = "Sono nello stesso array di rosso"
|
||||
|
||||
[[frutta]]
|
||||
nome = "banana"
|
||||
|
||||
[[frutto.colore]]
|
||||
nome = "giallo"
|
||||
nota = "Anche io sono un oggetto di un array, ma dentro banana"
|
||||
```
|
||||
|
||||
Ecco l'equivalente JSON dell'ultima tabella:
|
||||
|
||||
```json
|
||||
{
|
||||
"frutta": [
|
||||
{
|
||||
"nome": "mela",
|
||||
"geometria": { "forma": "sferica", "nota": "..."},
|
||||
"colore": [
|
||||
{ "nome": "rosso", "nota": "..." },
|
||||
{ "nome": "verde", "nota": "..." }
|
||||
]
|
||||
},
|
||||
{
|
||||
"nome": "banana",
|
||||
"colore": [
|
||||
{ "nome": "giallo", "nota": "..." }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Altre risorse
|
||||
|
||||
+ [Repository ufficiale di TOML](https://github.com/toml-lang/toml)
|
||||
|
@ -1,246 +1,246 @@
|
||||
---
|
||||
category: tool
|
||||
tool: make
|
||||
contributors:
|
||||
- ["Robert Steed", "https://github.com/robochat"]
|
||||
- ["Stephan Fuhrmann", "https://github.com/sfuhrm"]
|
||||
filename: Makefile
|
||||
---
|
||||
|
||||
A Makefile defines a graph of rules for creating a target (or targets).
|
||||
Its purpose is to do the minimum amount of work needed to update a
|
||||
target to the most recent version of the source. Famously written over a
|
||||
weekend by Stuart Feldman in 1976, it is still widely used (particularly
|
||||
on Unix and Linux) despite many competitors and criticisms.
|
||||
|
||||
There are many varieties of make in existence, however this article
|
||||
assumes that we are using GNU make which is the standard on Linux.
|
||||
|
||||
```make
|
||||
|
||||
# Comments can be written like this.
|
||||
|
||||
# File should be named Makefile and then can be run as `make <target>`.
|
||||
# Otherwise we use `make -f "filename" <target>`.
|
||||
|
||||
# Warning - only use TABS to indent in Makefiles, never spaces!
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Basics
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# Rules are of the format
|
||||
# target: <prerequisite>
|
||||
# where prerequisites are optional.
|
||||
|
||||
# A rule - this rule will only run if file0.txt doesn't exist.
|
||||
file0.txt:
|
||||
echo "foo" > file0.txt
|
||||
# Even comments in these 'recipe' sections get passed to the shell.
|
||||
# Try `make file0.txt` or simply `make` - first rule is the default.
|
||||
|
||||
# This rule will only run if file0.txt is newer than file1.txt.
|
||||
file1.txt: file0.txt
|
||||
cat file0.txt > file1.txt
|
||||
# use the same quoting rules as in the shell.
|
||||
@cat file0.txt >> file1.txt
|
||||
# @ stops the command from being echoed to stdout.
|
||||
-@echo 'hello'
|
||||
# - means that make will keep going in the case of an error.
|
||||
# Try `make file1.txt` on the commandline.
|
||||
|
||||
# A rule can have multiple targets and multiple prerequisites
|
||||
file2.txt file3.txt: file0.txt file1.txt
|
||||
touch file2.txt
|
||||
touch file3.txt
|
||||
|
||||
# Make will complain about multiple recipes for the same rule. Empty
|
||||
# recipes don't count though and can be used to add new dependencies.
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Phony Targets
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# A phony target. Any target that isn't a file.
|
||||
# It will never be up to date so make will always try to run it.
|
||||
all: maker process
|
||||
|
||||
# We can declare things out of order.
|
||||
maker:
|
||||
touch ex0.txt ex1.txt
|
||||
|
||||
# Can avoid phony rules breaking when a real file has the same name by
|
||||
.PHONY: all maker process
|
||||
# This is a special target. There are several others.
|
||||
|
||||
# A rule with a dependency on a phony target will always run
|
||||
ex0.txt ex1.txt: maker
|
||||
|
||||
# Common phony targets are: all make clean install ...
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Automatic Variables & Wildcards
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
process: file*.txt #using a wildcard to match filenames
|
||||
@echo $^ # $^ is a variable containing the list of prerequisites
|
||||
@echo $@ # prints the target name
|
||||
#(for multiple target rules, $@ is whichever caused the rule to run)
|
||||
@echo $< # the first prerequisite listed
|
||||
@echo $? # only the dependencies that are out of date
|
||||
@echo $+ # all dependencies including duplicates (unlike normal)
|
||||
#@echo $| # all of the 'order only' prerequisites
|
||||
|
||||
# Even if we split up the rule dependency definitions, $^ will find them
|
||||
process: ex1.txt file0.txt
|
||||
# ex1.txt will be found but file0.txt will be deduplicated.
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Patterns
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# Can teach make how to convert certain files into other files.
|
||||
|
||||
%.png: %.svg
|
||||
inkscape --export-png $^
|
||||
|
||||
# Pattern rules will only do anything if make decides to create the
|
||||
# target.
|
||||
|
||||
# Directory paths are normally ignored when matching pattern rules. But
|
||||
# make will try to use the most appropriate rule available.
|
||||
small/%.png: %.svg
|
||||
inkscape --export-png --export-dpi 30 $^
|
||||
|
||||
# make will use the last version for a pattern rule that it finds.
|
||||
%.png: %.svg
|
||||
@echo this rule is chosen
|
||||
|
||||
# However make will use the first pattern rule that can make the target
|
||||
%.png: %.ps
|
||||
@echo this rule is not chosen if *.svg and *.ps are both present
|
||||
|
||||
# make already has some pattern rules built-in. For instance, it knows
|
||||
# how to turn *.c files into *.o files.
|
||||
|
||||
# Older makefiles might use suffix rules instead of pattern rules
|
||||
.png.ps:
|
||||
@echo this rule is similar to a pattern rule.
|
||||
|
||||
# Tell make about the suffix rule
|
||||
.SUFFIXES: .png
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Variables
|
||||
#-----------------------------------------------------------------------
|
||||
# aka. macros
|
||||
|
||||
# Variables are basically all string types
|
||||
|
||||
name = Ted
|
||||
name2="Sarah"
|
||||
|
||||
echo:
|
||||
@echo $(name)
|
||||
@echo ${name2}
|
||||
@echo $name # This won't work, treated as $(n)ame.
|
||||
@echo $(name3) # Unknown variables are treated as empty strings.
|
||||
|
||||
# There are 4 places to set variables.
|
||||
# In order of priority from highest to lowest:
|
||||
# 1: commandline arguments
|
||||
# 2: Makefile
|
||||
# 3: shell environment variables - make imports these automatically.
|
||||
# 4: make has some predefined variables
|
||||
|
||||
name4 ?= Jean
|
||||
# Only set the variable if environment variable is not already defined.
|
||||
|
||||
override name5 = David
|
||||
# Stops commandline arguments from changing this variable.
|
||||
|
||||
name4 +=grey
|
||||
# Append values to variable (includes a space).
|
||||
|
||||
# Pattern-specific variable values (GNU extension).
|
||||
echo: name2 = Sara # True within the matching rule
|
||||
# and also within its remade recursive dependencies
|
||||
# (except it can break when your graph gets too complicated!)
|
||||
|
||||
# Some variables defined automatically by make.
|
||||
echo_inbuilt:
|
||||
echo $(CC)
|
||||
echo ${CXX}
|
||||
echo $(FC)
|
||||
echo ${CFLAGS}
|
||||
echo $(CPPFLAGS)
|
||||
echo ${CXXFLAGS}
|
||||
echo $(LDFLAGS)
|
||||
echo ${LDLIBS}
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Variables 2
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# The first type of variables are evaluated each time they are used.
|
||||
# This can be expensive, so a second type of variable exists which is
|
||||
# only evaluated once. (This is a GNU make extension)
|
||||
|
||||
var := hello
|
||||
var2 ::= $(var) hello
|
||||
#:= and ::= are equivalent.
|
||||
|
||||
# These variables are evaluated procedurally (in the order that they
|
||||
# appear), thus breaking with the rest of the language !
|
||||
|
||||
# This doesn't work
|
||||
var3 ::= $(var4) and good luck
|
||||
var4 ::= good night
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Functions
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# make has lots of functions available.
|
||||
|
||||
sourcefiles = $(wildcard *.c */*.c)
|
||||
objectfiles = $(patsubst %.c,%.o,$(sourcefiles))
|
||||
|
||||
# Format is $(func arg0,arg1,arg2...)
|
||||
|
||||
# Some examples
|
||||
ls: * src/*
|
||||
@echo $(filter %.txt, $^)
|
||||
@echo $(notdir $^)
|
||||
@echo $(join $(dir $^),$(notdir $^))
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Directives
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# Include other makefiles, useful for platform specific code
|
||||
include foo.mk
|
||||
|
||||
sport = tennis
|
||||
# Conditional compilation
|
||||
report:
|
||||
ifeq ($(sport),tennis)
|
||||
@echo 'game, set, match'
|
||||
else
|
||||
@echo "They think it's all over; it is now"
|
||||
endif
|
||||
|
||||
# There are also ifneq, ifdef, ifndef
|
||||
|
||||
foo = true
|
||||
|
||||
ifdef $(foo)
|
||||
bar = 'hello'
|
||||
endif
|
||||
```
|
||||
|
||||
### More Resources
|
||||
|
||||
+ [gnu make documentation](https://www.gnu.org/software/make/manual/)
|
||||
+ [software carpentry tutorial](http://swcarpentry.github.io/make-novice/)
|
||||
+ learn C the hard way [ex2](http://c.learncodethehardway.org/book/ex2.html) [ex28](http://c.learncodethehardway.org/book/ex28.html)
|
||||
---
|
||||
category: tool
|
||||
tool: make
|
||||
contributors:
|
||||
- ["Robert Steed", "https://github.com/robochat"]
|
||||
- ["Stephan Fuhrmann", "https://github.com/sfuhrm"]
|
||||
filename: Makefile
|
||||
---
|
||||
|
||||
A Makefile defines a graph of rules for creating a target (or targets).
|
||||
Its purpose is to do the minimum amount of work needed to update a
|
||||
target to the most recent version of the source. Famously written over a
|
||||
weekend by Stuart Feldman in 1976, it is still widely used (particularly
|
||||
on Unix and Linux) despite many competitors and criticisms.
|
||||
|
||||
There are many varieties of make in existence, however this article
|
||||
assumes that we are using GNU make which is the standard on Linux.
|
||||
|
||||
```make
|
||||
|
||||
# Comments can be written like this.
|
||||
|
||||
# File should be named Makefile and then can be run as `make <target>`.
|
||||
# Otherwise we use `make -f "filename" <target>`.
|
||||
|
||||
# Warning - only use TABS to indent in Makefiles, never spaces!
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Basics
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# Rules are of the format
|
||||
# target: <prerequisite>
|
||||
# where prerequisites are optional.
|
||||
|
||||
# A rule - this rule will only run if file0.txt doesn't exist.
|
||||
file0.txt:
|
||||
echo "foo" > file0.txt
|
||||
# Even comments in these 'recipe' sections get passed to the shell.
|
||||
# Try `make file0.txt` or simply `make` - first rule is the default.
|
||||
|
||||
# This rule will only run if file0.txt is newer than file1.txt.
|
||||
file1.txt: file0.txt
|
||||
cat file0.txt > file1.txt
|
||||
# use the same quoting rules as in the shell.
|
||||
@cat file0.txt >> file1.txt
|
||||
# @ stops the command from being echoed to stdout.
|
||||
-@echo 'hello'
|
||||
# - means that make will keep going in the case of an error.
|
||||
# Try `make file1.txt` on the commandline.
|
||||
|
||||
# A rule can have multiple targets and multiple prerequisites
|
||||
file2.txt file3.txt: file0.txt file1.txt
|
||||
touch file2.txt
|
||||
touch file3.txt
|
||||
|
||||
# Make will complain about multiple recipes for the same rule. Empty
|
||||
# recipes don't count though and can be used to add new dependencies.
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Phony Targets
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# A phony target. Any target that isn't a file.
|
||||
# It will never be up to date so make will always try to run it.
|
||||
all: maker process
|
||||
|
||||
# We can declare things out of order.
|
||||
maker:
|
||||
touch ex0.txt ex1.txt
|
||||
|
||||
# Can avoid phony rules breaking when a real file has the same name by
|
||||
.PHONY: all maker process
|
||||
# This is a special target. There are several others.
|
||||
|
||||
# A rule with a dependency on a phony target will always run
|
||||
ex0.txt ex1.txt: maker
|
||||
|
||||
# Common phony targets are: all make clean install ...
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Automatic Variables & Wildcards
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
process: file*.txt #using a wildcard to match filenames
|
||||
@echo $^ # $^ is a variable containing the list of prerequisites
|
||||
@echo $@ # prints the target name
|
||||
#(for multiple target rules, $@ is whichever caused the rule to run)
|
||||
@echo $< # the first prerequisite listed
|
||||
@echo $? # only the dependencies that are out of date
|
||||
@echo $+ # all dependencies including duplicates (unlike normal)
|
||||
#@echo $| # all of the 'order only' prerequisites
|
||||
|
||||
# Even if we split up the rule dependency definitions, $^ will find them
|
||||
process: ex1.txt file0.txt
|
||||
# ex1.txt will be found but file0.txt will be deduplicated.
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Patterns
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# Can teach make how to convert certain files into other files.
|
||||
|
||||
%.png: %.svg
|
||||
inkscape --export-png $^
|
||||
|
||||
# Pattern rules will only do anything if make decides to create the
|
||||
# target.
|
||||
|
||||
# Directory paths are normally ignored when matching pattern rules. But
|
||||
# make will try to use the most appropriate rule available.
|
||||
small/%.png: %.svg
|
||||
inkscape --export-png --export-dpi 30 $^
|
||||
|
||||
# make will use the last version for a pattern rule that it finds.
|
||||
%.png: %.svg
|
||||
@echo this rule is chosen
|
||||
|
||||
# However make will use the first pattern rule that can make the target
|
||||
%.png: %.ps
|
||||
@echo this rule is not chosen if *.svg and *.ps are both present
|
||||
|
||||
# make already has some pattern rules built-in. For instance, it knows
|
||||
# how to turn *.c files into *.o files.
|
||||
|
||||
# Older makefiles might use suffix rules instead of pattern rules
|
||||
.png.ps:
|
||||
@echo this rule is similar to a pattern rule.
|
||||
|
||||
# Tell make about the suffix rule
|
||||
.SUFFIXES: .png
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Variables
|
||||
#-----------------------------------------------------------------------
|
||||
# aka. macros
|
||||
|
||||
# Variables are basically all string types
|
||||
|
||||
name = Ted
|
||||
name2="Sarah"
|
||||
|
||||
echo:
|
||||
@echo $(name)
|
||||
@echo ${name2}
|
||||
@echo $name # This won't work, treated as $(n)ame.
|
||||
@echo $(name3) # Unknown variables are treated as empty strings.
|
||||
|
||||
# There are 4 places to set variables.
|
||||
# In order of priority from highest to lowest:
|
||||
# 1: commandline arguments
|
||||
# 2: Makefile
|
||||
# 3: shell environment variables - make imports these automatically.
|
||||
# 4: make has some predefined variables
|
||||
|
||||
name4 ?= Jean
|
||||
# Only set the variable if environment variable is not already defined.
|
||||
|
||||
override name5 = David
|
||||
# Stops commandline arguments from changing this variable.
|
||||
|
||||
name4 +=grey
|
||||
# Append values to variable (includes a space).
|
||||
|
||||
# Pattern-specific variable values (GNU extension).
|
||||
echo: name2 = Sara # True within the matching rule
|
||||
# and also within its remade recursive dependencies
|
||||
# (except it can break when your graph gets too complicated!)
|
||||
|
||||
# Some variables defined automatically by make.
|
||||
echo_inbuilt:
|
||||
echo $(CC)
|
||||
echo ${CXX}
|
||||
echo $(FC)
|
||||
echo ${CFLAGS}
|
||||
echo $(CPPFLAGS)
|
||||
echo ${CXXFLAGS}
|
||||
echo $(LDFLAGS)
|
||||
echo ${LDLIBS}
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Variables 2
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# The first type of variables are evaluated each time they are used.
|
||||
# This can be expensive, so a second type of variable exists which is
|
||||
# only evaluated once. (This is a GNU make extension)
|
||||
|
||||
var := hello
|
||||
var2 ::= $(var) hello
|
||||
#:= and ::= are equivalent.
|
||||
|
||||
# These variables are evaluated procedurally (in the order that they
|
||||
# appear), thus breaking with the rest of the language !
|
||||
|
||||
# This doesn't work
|
||||
var3 ::= $(var4) and good luck
|
||||
var4 ::= good night
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Functions
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# make has lots of functions available.
|
||||
|
||||
sourcefiles = $(wildcard *.c */*.c)
|
||||
objectfiles = $(patsubst %.c,%.o,$(sourcefiles))
|
||||
|
||||
# Format is $(func arg0,arg1,arg2...)
|
||||
|
||||
# Some examples
|
||||
ls: * src/*
|
||||
@echo $(filter %.txt, $^)
|
||||
@echo $(notdir $^)
|
||||
@echo $(join $(dir $^),$(notdir $^))
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Directives
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# Include other makefiles, useful for platform specific code
|
||||
include foo.mk
|
||||
|
||||
sport = tennis
|
||||
# Conditional compilation
|
||||
report:
|
||||
ifeq ($(sport),tennis)
|
||||
@echo 'game, set, match'
|
||||
else
|
||||
@echo "They think it's all over; it is now"
|
||||
endif
|
||||
|
||||
# There are also ifneq, ifdef, ifndef
|
||||
|
||||
foo = true
|
||||
|
||||
ifdef $(foo)
|
||||
bar = 'hello'
|
||||
endif
|
||||
```
|
||||
|
||||
### More Resources
|
||||
|
||||
+ [gnu make documentation](https://www.gnu.org/software/make/manual/)
|
||||
+ [software carpentry tutorial](http://swcarpentry.github.io/make-novice/)
|
||||
+ learn C the hard way [ex2](http://c.learncodethehardway.org/book/ex2.html) [ex28](http://c.learncodethehardway.org/book/ex28.html)
|
||||
|
1530
opengl.html.markdown
1530
opengl.html.markdown
File diff suppressed because it is too large
Load Diff
@ -1,245 +1,245 @@
|
||||
---
|
||||
category: tool
|
||||
tool: make
|
||||
contributors:
|
||||
- ["Robert Steed", "https://github.com/robochat"]
|
||||
- ["Stephan Fuhrmann", "https://github.com/sfuhrm"]
|
||||
translators:
|
||||
- ["Rogério Gomes Rio", "https://github.com/rogerlista"]
|
||||
filename: Makefile-pt
|
||||
|
||||
lang: pt-br
|
||||
---
|
||||
|
||||
Um Makefile define um gráfico de regras para criar um alvo (ou alvos). Sua finalidade é fazer o mínimo de trabalho necessário para atualizar um alvo para a versão mais recente da fonte. Famosamente escrito ao longo de um fim de semana por Stuart Feldman em 1976, ainda é amplamente usada (particularmente no Unix e no Linux) apesar de muitos concorrentes e críticas.
|
||||
|
||||
Existem muitas variedades de make na existência, no entanto, este artigo pressupõe que estamos usando o GNU make, que é o padrão no Linux.
|
||||
|
||||
```make
|
||||
|
||||
# Comentários podem ser escritos assim.
|
||||
|
||||
# O arquivo deve ser nomeado Makefile e então pode ser executado como `make <alvo>`.
|
||||
# Caso contrário, nós usamos `make -f "nome-do-arquivo" <alvo>`.
|
||||
|
||||
# Aviso - use somente TABS para identar em Makefiles, nunca espaços!
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Noções básicas
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# Regras são do formato
|
||||
# alvo: <pré-requisito>
|
||||
# onde os pré-requisitos são opcionais.
|
||||
|
||||
# Uma regra - esta regra só será executada se o arquivo0.txt não existir.
|
||||
arquivo0.txt:
|
||||
echo "foo" > arquivo0.txt
|
||||
# Mesmo os comentários nestas seções da 'receita' são passados para o shell.
|
||||
# Experimentar `make arquivo0.txt` or simplyou simplesmente `make` - primeira regra é o padrão.
|
||||
|
||||
# Esta regra só será executada se arquivo0.txt for mais recente que arquivo1.txt.
|
||||
arquivo1.txt: arquivo0.txt
|
||||
cat arquivo0.txt > arquivo1.txt
|
||||
# se as mesmas regras de citação do shell.
|
||||
@cat arquivo0.txt >> arquivo1.txt
|
||||
# @ pára o comando de ser ecoado para stdout.
|
||||
-@echo 'hello'
|
||||
# - significa que make continuará em caso de erro.
|
||||
# Experimentar `make arquivo1.txt` na linha de comando.
|
||||
|
||||
# Uma regra pode ter vários alvos e vários pré-requisitos
|
||||
arquivo2.txt arquivo3.txt: arquivo0.txt arquivo1.txt
|
||||
touch arquivo2.txt
|
||||
touch arquivo3.txt
|
||||
|
||||
# Make vai reclamar sobre várias receitas para a mesma regra. Esvaziar
|
||||
# receitas não contam e podem ser usadas para adicionar novas dependências.
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Alvos falsos
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# Um alvo falso. Qualquer alvo que não seja um arquivo.
|
||||
# Ele nunca será atualizado, portanto, o make sempre tentará executá-lo.
|
||||
all: maker process
|
||||
|
||||
# Podemos declarar as coisas fora de ordem.
|
||||
maker:
|
||||
touch ex0.txt ex1.txt
|
||||
|
||||
# Pode evitar quebrar regras falsas quando um arquivo real tem o mesmo nome
|
||||
.PHONY: all maker process
|
||||
# Este é um alvo especial. Existem vários outros.
|
||||
|
||||
# Uma regra com dependência de um alvo falso sempre será executada
|
||||
ex0.txt ex1.txt: maker
|
||||
|
||||
# Alvos falsos comuns são: todos fazem instalação limpa ...
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Variáveis Automáticas e Curingas
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
process: Arquivo*.txt # Usando um curinga para corresponder nomes de arquivos
|
||||
@echo $^ # $^ é uma variável que contém a lista de pré-requisitos
|
||||
@echo $@ # imprime o nome do alvo
|
||||
#(fpara várias regras alvo, $@ é o que causou a execução da regra)
|
||||
@echo $< # o primeiro pré-requisito listado
|
||||
@echo $? # somente as dependências que estão desatualizadas
|
||||
@echo $+ # todas as dependências, incluindo duplicadas (ao contrário do normal)
|
||||
#@echo $| # todos os pré-requisitos 'somente pedidos'
|
||||
|
||||
# Mesmo se dividirmos as definições de dependência de regra, $^ vai encontrá-los
|
||||
process: ex1.txt arquivo0.txt
|
||||
# ex1.txt será encontrado, mas arquivo0.txt será desduplicado.
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Padrões
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# Pode ensinar make a converter certos arquivos em outros arquivos.
|
||||
|
||||
%.png: %.svg
|
||||
inkscape --export-png $^
|
||||
|
||||
# As regras padrões só farão qualquer coisa se decidirem criar o alvo.
|
||||
|
||||
# Os caminhos de diretório são normalmente ignorados quando as regras de
|
||||
# padrões são correspondentes. Mas make tentará usar a regra mais
|
||||
# apropriada disponível.
|
||||
small/%.png: %.svg
|
||||
inkscape --export-png --export-dpi 30 $^
|
||||
|
||||
# make utilizará a última versão para uma regra de padrão que encontrar.
|
||||
%.png: %.svg
|
||||
@echo esta regra é escolhida
|
||||
|
||||
# No entanto, o make usará a primeira regra padrão que pode se tornar o alvo
|
||||
%.png: %.ps
|
||||
@echo esta regra não é escolhida se *.svg and *.ps estão ambos presentes
|
||||
|
||||
# make já tem algumas regras padrões embutidas. Por exemplo, ele sabe
|
||||
# como transformar arquivos *.c em arquivos *.o.
|
||||
|
||||
# Makefiles antigos podem usar regras de sufixo em vez de regras padrões
|
||||
.png.ps:
|
||||
@echo essa regra é semelhante a uma regra de padrão.
|
||||
|
||||
# make sobre a regra de sufixo
|
||||
.SUFFIXES: .png
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Variáveis
|
||||
#-----------------------------------------------------------------------
|
||||
# aka. macros
|
||||
|
||||
# As variáveis são basicamente todos os tipos de string
|
||||
|
||||
name = Ted
|
||||
name2="Sarah"
|
||||
|
||||
echo:
|
||||
@echo $(name)
|
||||
@echo ${name2}
|
||||
@echo $name # Isso não funcionará, tratado como $ (n)ame.
|
||||
@echo $(name3) # Variáveis desconhecidas são tratadas como strings vazias.
|
||||
|
||||
# Existem 4 lugares para definir variáveis.
|
||||
# Em ordem de prioridade, do maior para o menor:
|
||||
# 1: argumentos de linha de comando
|
||||
# 2: Makefile
|
||||
# 3: variáveis de ambiente do shell - faça importações automaticamente.
|
||||
# 4: make tem algumas variáveis predefinidas
|
||||
|
||||
name4 ?= Jean
|
||||
# Somente defina a variável se a variável de ambiente ainda não estiver definida.
|
||||
|
||||
override name5 = David
|
||||
# Pára os argumentos da linha de comando de alterar essa variável.
|
||||
|
||||
name4 +=grey
|
||||
# Anexar valores à variável (inclui um espaço).
|
||||
|
||||
# Valores variáveis específicos de padrões (extensão GNU).
|
||||
echo: name2 = Sara # Verdadeiro dentro da regra de correspondência
|
||||
# e também dentro de suas recursivas dependências
|
||||
# (exceto que ele pode quebrar quando seu gráfico ficar muito complicado!)
|
||||
|
||||
# Algumas variáveis definidas automaticamente pelo make
|
||||
echo_inbuilt:
|
||||
echo $(CC)
|
||||
echo ${CXX}
|
||||
echo $(FC)
|
||||
echo ${CFLAGS}
|
||||
echo $(CPPFLAGS)
|
||||
echo ${CXXFLAGS}
|
||||
echo $(LDFLAGS)
|
||||
echo ${LDLIBS}
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Variáveis 2
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# O primeiro tipo de variáveis é avaliado a cada vez que elas são usadas.
|
||||
# TIsso pode ser caro, então existe um segundo tipo de variável que é
|
||||
# avaliado apenas uma vez. (Esta é uma extensão do GNU make)
|
||||
|
||||
var := hello
|
||||
var2 ::= $(var) hello
|
||||
#:= e ::= são equivalentes.
|
||||
|
||||
# Essas variáveis são avaliadas procedimentalmente (na ordem em que
|
||||
# aparecem), quebrando assim o resto da línguagem!
|
||||
|
||||
# Isso não funciona
|
||||
var3 ::= $(var4) and good luck
|
||||
var4 ::= good night
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Funções
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# make tem muitas funções disponíveis.
|
||||
|
||||
sourcefiles = $(wildcard *.c */*.c)
|
||||
objectfiles = $(patsubst %.c,%.o,$(sourcefiles))
|
||||
|
||||
# O formato é $(func arg0,arg1,arg2...)
|
||||
|
||||
# Alguns exemplos
|
||||
ls: * src/*
|
||||
@echo $(filter %.txt, $^)
|
||||
@echo $(notdir $^)
|
||||
@echo $(join $(dir $^),$(notdir $^))
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Diretivas
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# Inclua outros makefiles, úteis para código específico da plataforma
|
||||
include foo.mk
|
||||
|
||||
sport = tennis
|
||||
# Compilação condicional
|
||||
report:
|
||||
ifeq ($(sport),tennis)
|
||||
@echo 'game, set, match'
|
||||
else
|
||||
@echo "They think it's all over; it is now"
|
||||
endif
|
||||
|
||||
# Há também ifneq, ifdef, ifndef
|
||||
|
||||
foo = true
|
||||
|
||||
ifdef $(foo)
|
||||
bar = 'hello'
|
||||
endif
|
||||
```
|
||||
|
||||
### More Resources
|
||||
|
||||
+ [documentação gnu make](https://www.gnu.org/software/make/manual/)
|
||||
+ [tutorial de carpintaria de software](http://swcarpentry.github.io/make-novice/)
|
||||
+ aprenda C da maneira mais difícil [ex2](http://c.learncodethehardway.org/book/ex2.html) [ex28](http://c.learncodethehardway.org/book/ex28.html)
|
||||
---
|
||||
category: tool
|
||||
tool: make
|
||||
contributors:
|
||||
- ["Robert Steed", "https://github.com/robochat"]
|
||||
- ["Stephan Fuhrmann", "https://github.com/sfuhrm"]
|
||||
translators:
|
||||
- ["Rogério Gomes Rio", "https://github.com/rogerlista"]
|
||||
filename: Makefile-pt
|
||||
|
||||
lang: pt-br
|
||||
---
|
||||
|
||||
Um Makefile define um gráfico de regras para criar um alvo (ou alvos). Sua finalidade é fazer o mínimo de trabalho necessário para atualizar um alvo para a versão mais recente da fonte. Famosamente escrito ao longo de um fim de semana por Stuart Feldman em 1976, ainda é amplamente usada (particularmente no Unix e no Linux) apesar de muitos concorrentes e críticas.
|
||||
|
||||
Existem muitas variedades de make na existência, no entanto, este artigo pressupõe que estamos usando o GNU make, que é o padrão no Linux.
|
||||
|
||||
```make
|
||||
|
||||
# Comentários podem ser escritos assim.
|
||||
|
||||
# O arquivo deve ser nomeado Makefile e então pode ser executado como `make <alvo>`.
|
||||
# Caso contrário, nós usamos `make -f "nome-do-arquivo" <alvo>`.
|
||||
|
||||
# Aviso - use somente TABS para identar em Makefiles, nunca espaços!
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Noções básicas
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# Regras são do formato
|
||||
# alvo: <pré-requisito>
|
||||
# onde os pré-requisitos são opcionais.
|
||||
|
||||
# Uma regra - esta regra só será executada se o arquivo0.txt não existir.
|
||||
arquivo0.txt:
|
||||
echo "foo" > arquivo0.txt
|
||||
# Mesmo os comentários nestas seções da 'receita' são passados para o shell.
|
||||
# Experimentar `make arquivo0.txt` or simplyou simplesmente `make` - primeira regra é o padrão.
|
||||
|
||||
# Esta regra só será executada se arquivo0.txt for mais recente que arquivo1.txt.
|
||||
arquivo1.txt: arquivo0.txt
|
||||
cat arquivo0.txt > arquivo1.txt
|
||||
# se as mesmas regras de citação do shell.
|
||||
@cat arquivo0.txt >> arquivo1.txt
|
||||
# @ pára o comando de ser ecoado para stdout.
|
||||
-@echo 'hello'
|
||||
# - significa que make continuará em caso de erro.
|
||||
# Experimentar `make arquivo1.txt` na linha de comando.
|
||||
|
||||
# Uma regra pode ter vários alvos e vários pré-requisitos
|
||||
arquivo2.txt arquivo3.txt: arquivo0.txt arquivo1.txt
|
||||
touch arquivo2.txt
|
||||
touch arquivo3.txt
|
||||
|
||||
# Make vai reclamar sobre várias receitas para a mesma regra. Esvaziar
|
||||
# receitas não contam e podem ser usadas para adicionar novas dependências.
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Alvos falsos
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# Um alvo falso. Qualquer alvo que não seja um arquivo.
|
||||
# Ele nunca será atualizado, portanto, o make sempre tentará executá-lo.
|
||||
all: maker process
|
||||
|
||||
# Podemos declarar as coisas fora de ordem.
|
||||
maker:
|
||||
touch ex0.txt ex1.txt
|
||||
|
||||
# Pode evitar quebrar regras falsas quando um arquivo real tem o mesmo nome
|
||||
.PHONY: all maker process
|
||||
# Este é um alvo especial. Existem vários outros.
|
||||
|
||||
# Uma regra com dependência de um alvo falso sempre será executada
|
||||
ex0.txt ex1.txt: maker
|
||||
|
||||
# Alvos falsos comuns são: todos fazem instalação limpa ...
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Variáveis Automáticas e Curingas
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
process: Arquivo*.txt # Usando um curinga para corresponder nomes de arquivos
|
||||
@echo $^ # $^ é uma variável que contém a lista de pré-requisitos
|
||||
@echo $@ # imprime o nome do alvo
|
||||
#(fpara várias regras alvo, $@ é o que causou a execução da regra)
|
||||
@echo $< # o primeiro pré-requisito listado
|
||||
@echo $? # somente as dependências que estão desatualizadas
|
||||
@echo $+ # todas as dependências, incluindo duplicadas (ao contrário do normal)
|
||||
#@echo $| # todos os pré-requisitos 'somente pedidos'
|
||||
|
||||
# Mesmo se dividirmos as definições de dependência de regra, $^ vai encontrá-los
|
||||
process: ex1.txt arquivo0.txt
|
||||
# ex1.txt será encontrado, mas arquivo0.txt será desduplicado.
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Padrões
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# Pode ensinar make a converter certos arquivos em outros arquivos.
|
||||
|
||||
%.png: %.svg
|
||||
inkscape --export-png $^
|
||||
|
||||
# As regras padrões só farão qualquer coisa se decidirem criar o alvo.
|
||||
|
||||
# Os caminhos de diretório são normalmente ignorados quando as regras de
|
||||
# padrões são correspondentes. Mas make tentará usar a regra mais
|
||||
# apropriada disponível.
|
||||
small/%.png: %.svg
|
||||
inkscape --export-png --export-dpi 30 $^
|
||||
|
||||
# make utilizará a última versão para uma regra de padrão que encontrar.
|
||||
%.png: %.svg
|
||||
@echo esta regra é escolhida
|
||||
|
||||
# No entanto, o make usará a primeira regra padrão que pode se tornar o alvo
|
||||
%.png: %.ps
|
||||
@echo esta regra não é escolhida se *.svg and *.ps estão ambos presentes
|
||||
|
||||
# make já tem algumas regras padrões embutidas. Por exemplo, ele sabe
|
||||
# como transformar arquivos *.c em arquivos *.o.
|
||||
|
||||
# Makefiles antigos podem usar regras de sufixo em vez de regras padrões
|
||||
.png.ps:
|
||||
@echo essa regra é semelhante a uma regra de padrão.
|
||||
|
||||
# make sobre a regra de sufixo
|
||||
.SUFFIXES: .png
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Variáveis
|
||||
#-----------------------------------------------------------------------
|
||||
# aka. macros
|
||||
|
||||
# As variáveis são basicamente todos os tipos de string
|
||||
|
||||
name = Ted
|
||||
name2="Sarah"
|
||||
|
||||
echo:
|
||||
@echo $(name)
|
||||
@echo ${name2}
|
||||
@echo $name # Isso não funcionará, tratado como $ (n)ame.
|
||||
@echo $(name3) # Variáveis desconhecidas são tratadas como strings vazias.
|
||||
|
||||
# Existem 4 lugares para definir variáveis.
|
||||
# Em ordem de prioridade, do maior para o menor:
|
||||
# 1: argumentos de linha de comando
|
||||
# 2: Makefile
|
||||
# 3: variáveis de ambiente do shell - faça importações automaticamente.
|
||||
# 4: make tem algumas variáveis predefinidas
|
||||
|
||||
name4 ?= Jean
|
||||
# Somente defina a variável se a variável de ambiente ainda não estiver definida.
|
||||
|
||||
override name5 = David
|
||||
# Pára os argumentos da linha de comando de alterar essa variável.
|
||||
|
||||
name4 +=grey
|
||||
# Anexar valores à variável (inclui um espaço).
|
||||
|
||||
# Valores variáveis específicos de padrões (extensão GNU).
|
||||
echo: name2 = Sara # Verdadeiro dentro da regra de correspondência
|
||||
# e também dentro de suas recursivas dependências
|
||||
# (exceto que ele pode quebrar quando seu gráfico ficar muito complicado!)
|
||||
|
||||
# Algumas variáveis definidas automaticamente pelo make
|
||||
echo_inbuilt:
|
||||
echo $(CC)
|
||||
echo ${CXX}
|
||||
echo $(FC)
|
||||
echo ${CFLAGS}
|
||||
echo $(CPPFLAGS)
|
||||
echo ${CXXFLAGS}
|
||||
echo $(LDFLAGS)
|
||||
echo ${LDLIBS}
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Variáveis 2
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# O primeiro tipo de variáveis é avaliado a cada vez que elas são usadas.
|
||||
# TIsso pode ser caro, então existe um segundo tipo de variável que é
|
||||
# avaliado apenas uma vez. (Esta é uma extensão do GNU make)
|
||||
|
||||
var := hello
|
||||
var2 ::= $(var) hello
|
||||
#:= e ::= são equivalentes.
|
||||
|
||||
# Essas variáveis são avaliadas procedimentalmente (na ordem em que
|
||||
# aparecem), quebrando assim o resto da línguagem!
|
||||
|
||||
# Isso não funciona
|
||||
var3 ::= $(var4) and good luck
|
||||
var4 ::= good night
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Funções
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# make tem muitas funções disponíveis.
|
||||
|
||||
sourcefiles = $(wildcard *.c */*.c)
|
||||
objectfiles = $(patsubst %.c,%.o,$(sourcefiles))
|
||||
|
||||
# O formato é $(func arg0,arg1,arg2...)
|
||||
|
||||
# Alguns exemplos
|
||||
ls: * src/*
|
||||
@echo $(filter %.txt, $^)
|
||||
@echo $(notdir $^)
|
||||
@echo $(join $(dir $^),$(notdir $^))
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Diretivas
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# Inclua outros makefiles, úteis para código específico da plataforma
|
||||
include foo.mk
|
||||
|
||||
sport = tennis
|
||||
# Compilação condicional
|
||||
report:
|
||||
ifeq ($(sport),tennis)
|
||||
@echo 'game, set, match'
|
||||
else
|
||||
@echo "They think it's all over; it is now"
|
||||
endif
|
||||
|
||||
# Há também ifneq, ifdef, ifndef
|
||||
|
||||
foo = true
|
||||
|
||||
ifdef $(foo)
|
||||
bar = 'hello'
|
||||
endif
|
||||
```
|
||||
|
||||
### More Resources
|
||||
|
||||
+ [documentação gnu make](https://www.gnu.org/software/make/manual/)
|
||||
+ [tutorial de carpintaria de software](http://swcarpentry.github.io/make-novice/)
|
||||
+ aprenda C da maneira mais difícil [ex2](http://c.learncodethehardway.org/book/ex2.html) [ex28](http://c.learncodethehardway.org/book/ex28.html)
|
||||
|
@ -1,225 +1,225 @@
|
||||
---
|
||||
category: Algorithms & Data Structures
|
||||
name: Asymptotic Notation
|
||||
contributors:
|
||||
- ["Jake Prather", "http://github.com/JakeHP"]
|
||||
- ["Divay Prakash", "http://github.com/divayprakash"]
|
||||
translators:
|
||||
- ["pru-mike", "http://github.com/pru-mike"]
|
||||
lang: ru-ru
|
||||
---
|
||||
|
||||
# О-символика
|
||||
|
||||
## Что это такое?
|
||||
|
||||
О-символика, или асимптотическая запись, — это система символов, позволяющая
|
||||
оценить время выполнения алгоритма, устанавливая зависимость времени выполнения
|
||||
от увеличения объёма входных данных. Она также известна как оценка
|
||||
сложности алгоритмов. Станет ли алгоритм невероятно медленным, когда
|
||||
объём входных данных увеличится? Будет ли алгоритм выполняться достаточно быстро,
|
||||
если объём входных данных возрастёт? О-символика позволяет ответить на эти
|
||||
вопросы.
|
||||
|
||||
## Можно ли по-другому найти ответы на эти вопросы?
|
||||
|
||||
Один способ — это подсчитать число элементарных операций в зависимости от
|
||||
различных объёмов входных данных. Хотя это и приемлемое решение, тот объём
|
||||
работы, которого оно потребует, даже для простых алгоритмов делает его
|
||||
использование неоправданным.
|
||||
|
||||
Другой способ — это измерить, какое время алгоритм потребует для завершения на
|
||||
различных объёмах входных данных. В то же время, точность и относительность
|
||||
этого метода (полученное время будет относиться только к той машине, на которой
|
||||
оно вычислено) зависит от среды выполнения: компьютерного аппаратного
|
||||
обеспечения, мощности процессора и т.д.
|
||||
|
||||
## Виды О-символики
|
||||
|
||||
В первом разделе этого документа мы определили, что О-символика
|
||||
позволяет оценивать алгоритмы в зависимости от изменения размера входных
|
||||
данных. Представим, что алгоритм — это функция f, n — размер входных данных и
|
||||
f(n) — время выполнения. Тогда для данного алгоритма f с размером входных
|
||||
данных n получим какое-то результирующее время выполнения f(n).
|
||||
Из этого можно построить график, где ось y — время выполнения, ось x — размер входных
|
||||
данных, а точки на графике — это время выполнения для заданного размера входных
|
||||
данных.
|
||||
|
||||
С помощью О-символики можно оценить функцию или алгоритм
|
||||
несколькими различными способами. Например, можно оценить алгоритм исходя
|
||||
из нижней оценки, верхней оценки, тождественной оценки. Чаще всего встречается
|
||||
анализ на основе верхней оценки. Как правило, не используется нижняя оценка,
|
||||
потому что она не подходит под планируемые условия. Отличный пример — алгоритмы
|
||||
сортировки, особенно добавление элементов в древовидную структуру. Нижняя оценка
|
||||
большинства таких алгоритмов может быть дана как одна операция. В то время как в
|
||||
большинстве случаев добавляемые элементы должны быть отсортированы
|
||||
соответствующим образом при помощи дерева, что может потребовать обхода целой
|
||||
ветви. Это и есть худший случай, для которого планируется верхняя оценка.
|
||||
|
||||
### Виды функций, пределы и упрощения
|
||||
|
||||
```
|
||||
Логарифмическая функция — log n
|
||||
Линейная функция — an + b
|
||||
Квадратичная функция — an^2 + bn +c
|
||||
Степенная функция — an^z + . . . + an^2 + a*n^1 + a*n^0, где z — константа
|
||||
Показательная функция — a^n, где a — константа
|
||||
```
|
||||
|
||||
Приведены несколько базовых функций, используемых при определении сложности в
|
||||
различных оценках. Список начинается с самой медленно возрастающей функции
|
||||
(логарифм, наиболее быстрое время выполнения) и следует до самой быстро
|
||||
возрастающей функции (экспонента, самое медленное время выполнения). Отметим,
|
||||
что в то время, как «n», или размер входных данных, возрастает в каждой из этих функций,
|
||||
результат намного быстрее возрастает в квадратичной, степенной
|
||||
и показательной по сравнению с логарифмической и линейной.
|
||||
|
||||
Крайне важно понимать, что при использовании описанной далее нотации необходимо
|
||||
использовать упрощённые выражения.
|
||||
Это означает, что необходимо отбрасывать константы и слагаемые младших порядков,
|
||||
потому что если размер входных данных (n в функции f(n) нашего примера)
|
||||
увеличивается до бесконечности (в пределе), тогда слагаемые младших порядков
|
||||
и константы становятся пренебрежительно малыми. Таким образом, если есть
|
||||
константа, например, размера 2^9001 или любого другого невообразимого размера,
|
||||
надо понимать, что её упрощение внесёт значительные искажения в точность
|
||||
оценки.
|
||||
|
||||
Т.к. нам нужны упрощённые выражения, немного скорректируем нашу таблицу...
|
||||
|
||||
```
|
||||
Логарифм — log n
|
||||
Линейная функция — n
|
||||
Квадратичная функция — n^2
|
||||
Степенная функция — n^z, где z — константа
|
||||
Показательная функция — a^n, где a — константа
|
||||
```
|
||||
|
||||
### О Большое
|
||||
О Большое, записывается как **О**, — это асимптотическая запись для оценки худшего
|
||||
случая, или для ограничения заданной функции сверху. Это позволяет сделать
|
||||
_**асимптотическую оценку верхней границы**_ скорости роста времени выполнения
|
||||
алгоритма. Пусть `f(n)` — время выполнения алгоритма, а `g(n)` — заданная временная
|
||||
сложность, которая проверяется для алгоритма. Тогда `f(n)` — это O(g(n)), если
|
||||
существуют действительные константы c (c > 0) и n<sub>0</sub>, такие,
|
||||
что `f(n)` <= `c g(n)` выполняется для всех n, начиная с некоторого n<sub>0</sub> (n > n<sub>0</sub>).
|
||||
|
||||
*Пример 1*
|
||||
|
||||
```
|
||||
f(n) = 3log n + 100
|
||||
g(n) = log n
|
||||
```
|
||||
|
||||
Является ли `f(n)` O(g(n))?
|
||||
Является ли `3 log n + 100` O(log n)?
|
||||
Посмотрим на определение О Большого:
|
||||
|
||||
```
|
||||
3log n + 100 <= c * log n
|
||||
```
|
||||
|
||||
Существуют ли константы c и n<sub>0</sub>, такие, что выражение верно для всех n > n<sub>0</sub>?
|
||||
|
||||
```
|
||||
3log n + 100 <= 150 * log n, n > 2 (не определенно для n = 1)
|
||||
```
|
||||
|
||||
Да! По определению О Большого `f(n)` является O(g(n)).
|
||||
|
||||
*Пример 2*
|
||||
|
||||
```
|
||||
f(n) = 3 * n^2
|
||||
g(n) = n
|
||||
```
|
||||
|
||||
Является ли `f(n)` O(g(n))?
|
||||
Является ли `3 * n^2` O(n)?
|
||||
Посмотрим на определение О Большого:
|
||||
|
||||
```
|
||||
3 * n^2 <= c * n
|
||||
```
|
||||
|
||||
Существуют ли константы c и n<sub>0</sub>, такие, что выражение верно для всех n > n<sub>0</sub>?
|
||||
Нет, не существуют. `f(n)` НЕ ЯВЛЯЕТСЯ O(g(n)).
|
||||
|
||||
### Омега Большое
|
||||
Омега Большое, записывается как **Ω**, — это асимптотическая запись для оценки
|
||||
лучшего случая, или для ограничения заданной функции снизу. Это позволяет сделать
|
||||
_**асимптотическую оценку нижней границы**_ скорости роста времени выполнения
|
||||
алгоритма.
|
||||
|
||||
`f(n)` является Ω(g(n)), если существуют действительные константы
|
||||
c (c > 0) и n<sub>0</sub> (n<sub>0</sub> > 0), такие, что `f(n)` >= `c g(n)` для всех n > n<sub>0</sub>.
|
||||
|
||||
### Примечание
|
||||
|
||||
Асимптотические оценки, сделанные при помощи О Большого и Омега Большого, могут
|
||||
как являться, так и не являться точными. Для того чтобы обозначить, что границы не
|
||||
являются асимптотически точными, используются записи О Малое и Омега Малое.
|
||||
|
||||
### О Малое
|
||||
O Малое, записывается как **о**, — это асимптотическая запись для оценки верхней
|
||||
границы времени выполнения алгоритма при условии, что граница не является
|
||||
асимптотически точной.
|
||||
|
||||
`f(n)` является o(g(n)), если можно подобрать такие действительные константы,
|
||||
что для всех c (c > 0) найдётся n<sub>0</sub> (n<sub>0</sub> > 0), так
|
||||
что `f(n)` < `c g(n)` выполняется для всех n (n > n<sub>0</sub>).
|
||||
|
||||
Определения О-символики для О Большого и О Малого похожи. Главное отличие в том,
|
||||
что если f(n) = O(g(n)), тогда условие f(n) <= c g(n) выполняется, если _**существует**_
|
||||
константа c > 0, но если f(n) = o(g(n)), тогда условие f(n) < c g(n) выполняется
|
||||
для _**всех**_ констант c > 0.
|
||||
|
||||
### Омега Малое
|
||||
Омега Малое, записывается как **ω**, — это асимптотическая запись для оценки
|
||||
верхней границы времени выполнения алгоритма при условии, что граница не является
|
||||
асимптотически точной.
|
||||
|
||||
`f(n)` является ω(g(n)), если можно подобрать такие действительные константы,
|
||||
что для всех c (c > 0) найдётся n<sub>0</sub> (n<sub>0</sub> > 0), так
|
||||
что `f(n)` > `c g(n)` выполняется для всех n (n > n<sub>0</sub>).
|
||||
|
||||
Определения Ω-символики и ω-символики похожи. Главное отличие в том, что
|
||||
если f(n) = Ω(g(n)), тогда условие f(n) >= c g(n) выполняется, если _**существует**_
|
||||
константа c > 0, но если f(n) = ω(g(n)), тогда условие f(n) > c g(n)
|
||||
выполняется для _**всех**_ констант c > 0.
|
||||
|
||||
### Тета
|
||||
Тета, записывается как **Θ**, — это асимптотическая запись для оценки
|
||||
_***асимптотически точной границы***_ времени выполнения алгоритма.
|
||||
|
||||
`f(n)` является Θ(g(n)), если для некоторых действительных
|
||||
констант c1, c2 и n<sub>0</sub> (c1 > 0, c2 > 0, n<sub>0</sub> > 0)
|
||||
`c1 g(n)` < `f(n)` < `c2 g(n)` для всех n (n > n<sub>0</sub>).
|
||||
|
||||
∴ `f(n)` является Θ(g(n)) означает, что `f(n)` является O(g(n))
|
||||
и `f(n)` является Ω(g(n)).
|
||||
|
||||
О Большое — основной инструмент для анализа сложности алгоритмов.
|
||||
Также см. примеры по ссылкам.
|
||||
|
||||
### Заключение
|
||||
Такую тему сложно изложить кратко, поэтому обязательно стоит пройти по ссылкам и
|
||||
посмотреть дополнительную литературу. В ней даётся более глубокое описание с
|
||||
определениями и примерами.
|
||||
|
||||
|
||||
## Дополнительная литература
|
||||
|
||||
* [Алгоритмы на Java](https://www.ozon.ru/context/detail/id/18319699/)
|
||||
* [Алгоритмы. Построение и анализ](https://www.ozon.ru/context/detail/id/33769775/)
|
||||
|
||||
## Ссылки
|
||||
|
||||
* [Оценки времени исполнения. Символ O()](http://algolist.manual.ru/misc/o_n.php)
|
||||
* [Асимптотический анализ и теория вероятностей](https://www.lektorium.tv/course/22903)
|
||||
|
||||
## Ссылки (англ.)
|
||||
|
||||
* [Algorithms, Part I](https://www.coursera.org/learn/algorithms-part1)
|
||||
* [Cheatsheet 1](http://web.mit.edu/broder/Public/asymptotics-cheatsheet.pdf)
|
||||
* [Cheatsheet 2](http://bigocheatsheet.com/)
|
||||
|
||||
---
|
||||
category: Algorithms & Data Structures
|
||||
name: Asymptotic Notation
|
||||
contributors:
|
||||
- ["Jake Prather", "http://github.com/JakeHP"]
|
||||
- ["Divay Prakash", "http://github.com/divayprakash"]
|
||||
translators:
|
||||
- ["pru-mike", "http://github.com/pru-mike"]
|
||||
lang: ru-ru
|
||||
---
|
||||
|
||||
# О-символика
|
||||
|
||||
## Что это такое?
|
||||
|
||||
О-символика, или асимптотическая запись, — это система символов, позволяющая
|
||||
оценить время выполнения алгоритма, устанавливая зависимость времени выполнения
|
||||
от увеличения объёма входных данных. Она также известна как оценка
|
||||
сложности алгоритмов. Станет ли алгоритм невероятно медленным, когда
|
||||
объём входных данных увеличится? Будет ли алгоритм выполняться достаточно быстро,
|
||||
если объём входных данных возрастёт? О-символика позволяет ответить на эти
|
||||
вопросы.
|
||||
|
||||
## Можно ли по-другому найти ответы на эти вопросы?
|
||||
|
||||
Один способ — это подсчитать число элементарных операций в зависимости от
|
||||
различных объёмов входных данных. Хотя это и приемлемое решение, тот объём
|
||||
работы, которого оно потребует, даже для простых алгоритмов делает его
|
||||
использование неоправданным.
|
||||
|
||||
Другой способ — это измерить, какое время алгоритм потребует для завершения на
|
||||
различных объёмах входных данных. В то же время, точность и относительность
|
||||
этого метода (полученное время будет относиться только к той машине, на которой
|
||||
оно вычислено) зависит от среды выполнения: компьютерного аппаратного
|
||||
обеспечения, мощности процессора и т.д.
|
||||
|
||||
## Виды О-символики
|
||||
|
||||
В первом разделе этого документа мы определили, что О-символика
|
||||
позволяет оценивать алгоритмы в зависимости от изменения размера входных
|
||||
данных. Представим, что алгоритм — это функция f, n — размер входных данных и
|
||||
f(n) — время выполнения. Тогда для данного алгоритма f с размером входных
|
||||
данных n получим какое-то результирующее время выполнения f(n).
|
||||
Из этого можно построить график, где ось y — время выполнения, ось x — размер входных
|
||||
данных, а точки на графике — это время выполнения для заданного размера входных
|
||||
данных.
|
||||
|
||||
С помощью О-символики можно оценить функцию или алгоритм
|
||||
несколькими различными способами. Например, можно оценить алгоритм исходя
|
||||
из нижней оценки, верхней оценки, тождественной оценки. Чаще всего встречается
|
||||
анализ на основе верхней оценки. Как правило, не используется нижняя оценка,
|
||||
потому что она не подходит под планируемые условия. Отличный пример — алгоритмы
|
||||
сортировки, особенно добавление элементов в древовидную структуру. Нижняя оценка
|
||||
большинства таких алгоритмов может быть дана как одна операция. В то время как в
|
||||
большинстве случаев добавляемые элементы должны быть отсортированы
|
||||
соответствующим образом при помощи дерева, что может потребовать обхода целой
|
||||
ветви. Это и есть худший случай, для которого планируется верхняя оценка.
|
||||
|
||||
### Виды функций, пределы и упрощения
|
||||
|
||||
```
|
||||
Логарифмическая функция — log n
|
||||
Линейная функция — an + b
|
||||
Квадратичная функция — an^2 + bn +c
|
||||
Степенная функция — an^z + . . . + an^2 + a*n^1 + a*n^0, где z — константа
|
||||
Показательная функция — a^n, где a — константа
|
||||
```
|
||||
|
||||
Приведены несколько базовых функций, используемых при определении сложности в
|
||||
различных оценках. Список начинается с самой медленно возрастающей функции
|
||||
(логарифм, наиболее быстрое время выполнения) и следует до самой быстро
|
||||
возрастающей функции (экспонента, самое медленное время выполнения). Отметим,
|
||||
что в то время, как «n», или размер входных данных, возрастает в каждой из этих функций,
|
||||
результат намного быстрее возрастает в квадратичной, степенной
|
||||
и показательной по сравнению с логарифмической и линейной.
|
||||
|
||||
Крайне важно понимать, что при использовании описанной далее нотации необходимо
|
||||
использовать упрощённые выражения.
|
||||
Это означает, что необходимо отбрасывать константы и слагаемые младших порядков,
|
||||
потому что если размер входных данных (n в функции f(n) нашего примера)
|
||||
увеличивается до бесконечности (в пределе), тогда слагаемые младших порядков
|
||||
и константы становятся пренебрежительно малыми. Таким образом, если есть
|
||||
константа, например, размера 2^9001 или любого другого невообразимого размера,
|
||||
надо понимать, что её упрощение внесёт значительные искажения в точность
|
||||
оценки.
|
||||
|
||||
Т.к. нам нужны упрощённые выражения, немного скорректируем нашу таблицу...
|
||||
|
||||
```
|
||||
Логарифм — log n
|
||||
Линейная функция — n
|
||||
Квадратичная функция — n^2
|
||||
Степенная функция — n^z, где z — константа
|
||||
Показательная функция — a^n, где a — константа
|
||||
```
|
||||
|
||||
### О Большое
|
||||
О Большое, записывается как **О**, — это асимптотическая запись для оценки худшего
|
||||
случая, или для ограничения заданной функции сверху. Это позволяет сделать
|
||||
_**асимптотическую оценку верхней границы**_ скорости роста времени выполнения
|
||||
алгоритма. Пусть `f(n)` — время выполнения алгоритма, а `g(n)` — заданная временная
|
||||
сложность, которая проверяется для алгоритма. Тогда `f(n)` — это O(g(n)), если
|
||||
существуют действительные константы c (c > 0) и n<sub>0</sub>, такие,
|
||||
что `f(n)` <= `c g(n)` выполняется для всех n, начиная с некоторого n<sub>0</sub> (n > n<sub>0</sub>).
|
||||
|
||||
*Пример 1*
|
||||
|
||||
```
|
||||
f(n) = 3log n + 100
|
||||
g(n) = log n
|
||||
```
|
||||
|
||||
Является ли `f(n)` O(g(n))?
|
||||
Является ли `3 log n + 100` O(log n)?
|
||||
Посмотрим на определение О Большого:
|
||||
|
||||
```
|
||||
3log n + 100 <= c * log n
|
||||
```
|
||||
|
||||
Существуют ли константы c и n<sub>0</sub>, такие, что выражение верно для всех n > n<sub>0</sub>?
|
||||
|
||||
```
|
||||
3log n + 100 <= 150 * log n, n > 2 (не определенно для n = 1)
|
||||
```
|
||||
|
||||
Да! По определению О Большого `f(n)` является O(g(n)).
|
||||
|
||||
*Пример 2*
|
||||
|
||||
```
|
||||
f(n) = 3 * n^2
|
||||
g(n) = n
|
||||
```
|
||||
|
||||
Является ли `f(n)` O(g(n))?
|
||||
Является ли `3 * n^2` O(n)?
|
||||
Посмотрим на определение О Большого:
|
||||
|
||||
```
|
||||
3 * n^2 <= c * n
|
||||
```
|
||||
|
||||
Существуют ли константы c и n<sub>0</sub>, такие, что выражение верно для всех n > n<sub>0</sub>?
|
||||
Нет, не существуют. `f(n)` НЕ ЯВЛЯЕТСЯ O(g(n)).
|
||||
|
||||
### Омега Большое
|
||||
Омега Большое, записывается как **Ω**, — это асимптотическая запись для оценки
|
||||
лучшего случая, или для ограничения заданной функции снизу. Это позволяет сделать
|
||||
_**асимптотическую оценку нижней границы**_ скорости роста времени выполнения
|
||||
алгоритма.
|
||||
|
||||
`f(n)` является Ω(g(n)), если существуют действительные константы
|
||||
c (c > 0) и n<sub>0</sub> (n<sub>0</sub> > 0), такие, что `f(n)` >= `c g(n)` для всех n > n<sub>0</sub>.
|
||||
|
||||
### Примечание
|
||||
|
||||
Асимптотические оценки, сделанные при помощи О Большого и Омега Большого, могут
|
||||
как являться, так и не являться точными. Для того чтобы обозначить, что границы не
|
||||
являются асимптотически точными, используются записи О Малое и Омега Малое.
|
||||
|
||||
### О Малое
|
||||
O Малое, записывается как **о**, — это асимптотическая запись для оценки верхней
|
||||
границы времени выполнения алгоритма при условии, что граница не является
|
||||
асимптотически точной.
|
||||
|
||||
`f(n)` является o(g(n)), если можно подобрать такие действительные константы,
|
||||
что для всех c (c > 0) найдётся n<sub>0</sub> (n<sub>0</sub> > 0), так
|
||||
что `f(n)` < `c g(n)` выполняется для всех n (n > n<sub>0</sub>).
|
||||
|
||||
Определения О-символики для О Большого и О Малого похожи. Главное отличие в том,
|
||||
что если f(n) = O(g(n)), тогда условие f(n) <= c g(n) выполняется, если _**существует**_
|
||||
константа c > 0, но если f(n) = o(g(n)), тогда условие f(n) < c g(n) выполняется
|
||||
для _**всех**_ констант c > 0.
|
||||
|
||||
### Омега Малое
|
||||
Омега Малое, записывается как **ω**, — это асимптотическая запись для оценки
|
||||
верхней границы времени выполнения алгоритма при условии, что граница не является
|
||||
асимптотически точной.
|
||||
|
||||
`f(n)` является ω(g(n)), если можно подобрать такие действительные константы,
|
||||
что для всех c (c > 0) найдётся n<sub>0</sub> (n<sub>0</sub> > 0), так
|
||||
что `f(n)` > `c g(n)` выполняется для всех n (n > n<sub>0</sub>).
|
||||
|
||||
Определения Ω-символики и ω-символики похожи. Главное отличие в том, что
|
||||
если f(n) = Ω(g(n)), тогда условие f(n) >= c g(n) выполняется, если _**существует**_
|
||||
константа c > 0, но если f(n) = ω(g(n)), тогда условие f(n) > c g(n)
|
||||
выполняется для _**всех**_ констант c > 0.
|
||||
|
||||
### Тета
|
||||
Тета, записывается как **Θ**, — это асимптотическая запись для оценки
|
||||
_***асимптотически точной границы***_ времени выполнения алгоритма.
|
||||
|
||||
`f(n)` является Θ(g(n)), если для некоторых действительных
|
||||
констант c1, c2 и n<sub>0</sub> (c1 > 0, c2 > 0, n<sub>0</sub> > 0)
|
||||
`c1 g(n)` < `f(n)` < `c2 g(n)` для всех n (n > n<sub>0</sub>).
|
||||
|
||||
∴ `f(n)` является Θ(g(n)) означает, что `f(n)` является O(g(n))
|
||||
и `f(n)` является Ω(g(n)).
|
||||
|
||||
О Большое — основной инструмент для анализа сложности алгоритмов.
|
||||
Также см. примеры по ссылкам.
|
||||
|
||||
### Заключение
|
||||
Такую тему сложно изложить кратко, поэтому обязательно стоит пройти по ссылкам и
|
||||
посмотреть дополнительную литературу. В ней даётся более глубокое описание с
|
||||
определениями и примерами.
|
||||
|
||||
|
||||
## Дополнительная литература
|
||||
|
||||
* [Алгоритмы на Java](https://www.ozon.ru/context/detail/id/18319699/)
|
||||
* [Алгоритмы. Построение и анализ](https://www.ozon.ru/context/detail/id/33769775/)
|
||||
|
||||
## Ссылки
|
||||
|
||||
* [Оценки времени исполнения. Символ O()](http://algolist.manual.ru/misc/o_n.php)
|
||||
* [Асимптотический анализ и теория вероятностей](https://www.lektorium.tv/course/22903)
|
||||
|
||||
## Ссылки (англ.)
|
||||
|
||||
* [Algorithms, Part I](https://www.coursera.org/learn/algorithms-part1)
|
||||
* [Cheatsheet 1](http://web.mit.edu/broder/Public/asymptotics-cheatsheet.pdf)
|
||||
* [Cheatsheet 2](http://bigocheatsheet.com/)
|
||||
|
||||
|
@ -1,125 +1,125 @@
|
||||
---
|
||||
language: SQL
|
||||
contributors:
|
||||
- ["Metin Yalçınkaya", "https://github.com/mtnylnky"]
|
||||
lang: tr-tr
|
||||
filename: learnsql-tr.sql
|
||||
---
|
||||
|
||||
|
||||
```sql
|
||||
-- Yorumlar iki tire ile başlar
|
||||
|
||||
-- KISITLAR
|
||||
Not null -- Bir kolon asla boş olamaz
|
||||
default -- Boş olan yerlere varsayılan bir değer atar
|
||||
unique -- Bir kolondaki tüm değerlerin farklı olması kısıtlaması
|
||||
primary key -- Bir tablodaki her veri için kimlik bilgisi niteliğindedir
|
||||
check -- Bir kolondaki değerlerin belli bir kısıtlamayı sağlamasını sağlar
|
||||
|
||||
-- Tablo oluşturulur
|
||||
CREATE TABLE tablo1 ();
|
||||
|
||||
-- Tabloyu içerisinde kolonlar ile oluşturma
|
||||
CREATE TABLE tablo1(id INTEGER PRIMARY KEY NOT NULL UNIQUE, ad TEXT, soyad TEXT, yas INTEGER);
|
||||
|
||||
-- TABLO varlığını kontrol eder
|
||||
.table
|
||||
|
||||
-- Veri tabanında olan bütün tabloları görüntüler.
|
||||
.schema
|
||||
|
||||
-- Satır ekle
|
||||
INSERT INTO tablo1 ( ad, soyad) VALUES ("Deger1","Deger2");
|
||||
|
||||
-- Veritabanında tablo üzerindeki verileri görüntüle
|
||||
-- Sadece 'ad' gibi sınırlı bir veri için
|
||||
SELECT ad FROM tablo1;
|
||||
-- Bütün veriler için
|
||||
SELECT * FROM tablo1;
|
||||
|
||||
-- Veri güncelleme
|
||||
UPDATE tablo1 SET ad = "deger1-2"; WHERE name = "Deger1";
|
||||
|
||||
-- Satır sil
|
||||
DELETE FROM tablo1 WHERE id = 1;
|
||||
DELETE FROM tablo1 WHERE ad = "Deger1" OR ad = "Deger2";
|
||||
|
||||
-- Tabloya sonradan kolon ekleme
|
||||
ALTER TABLE tablo1 ADD COLUMN email TEXT;
|
||||
|
||||
-- Tablodaki kolon adı değiştirme
|
||||
EXEC sp_rename ' tablo1.[ad]', Ad, 'COLUMN';
|
||||
|
||||
-- Tablo adı değiştirme
|
||||
ALTER TABLE table1 RENAME TO Table1;
|
||||
|
||||
-- Tabloyu silme
|
||||
DROP TABLE Table1;
|
||||
|
||||
-- BİR TABLOYU BAŞKA TABLO KULLANARAK DOLDURMAK
|
||||
INSERT INTO Tablo2 SELECT id,ad, soyad, email from Tablo1;
|
||||
|
||||
-- LIKE KOMUTU
|
||||
-- Belirli bir kritere göre arama yaparken kullanılır
|
||||
-- Adı 'A' ile başlayan veriler
|
||||
SELECT * FROM tablo1 WHERE adi LIKE "A%";
|
||||
-- İçinde 'A' olan veriler
|
||||
SELECT * FROM tablo1 WHERE adi LIKE "%A%";
|
||||
|
||||
-- LIMIT KOMUTU
|
||||
-- Gösterilen satır sayısını sınırlamak için
|
||||
SELECT * FROM Tablo1 LIMIT 6;
|
||||
-- Gösterilen satırları belirli bir noktadan başlamak üzere sınırlamak için
|
||||
SELECT * FROM Tablo1 LIMIT 6 OFFSET 3;
|
||||
|
||||
-- ORDER BY KOMUTU
|
||||
-- Herhangi bir kolona göre gösterilen değerleri azalan veya artan şekilde sıralamak için
|
||||
SELECT kolon FROM tablo1 WHERE yas ORDER BY column1, column2, .. columnN] [ASC | DESC];
|
||||
SELECT * FROM Tablo1 ORDER BY yas ASC
|
||||
SELECT * FROM Tablo1 ORDER BY yas DESC
|
||||
|
||||
-- DISTINCT ANAHTAR SÖZCÜĞÜ
|
||||
-- Bu anahtar sözcükle sadece farklı değerler gösterilir.
|
||||
SELECT DISTINCT yas FROM tablo1;
|
||||
|
||||
-- JOIN KOMUTU
|
||||
-- CROSS JOIN
|
||||
-- Cross join bir tablodaki her satırı ikinci tablodaki bir satır ile eşleştirmek için kulanılır.
|
||||
-- Eğer birinci tabloda x satır ikinci tabloda y satır varsa sonuçta x*y satır olur.
|
||||
SELECT ... FROM table1 CROSS JOIN table2 …
|
||||
SELECT ad, yas FROM Tablo1 CROSS JOIN Tablo2;
|
||||
|
||||
-- INNER JOIN
|
||||
-- Inner join iki tablodaki ortak kolon değerlerini kullanarak bir sonuç üretir.
|
||||
SELECT ... FROM table1 [INNER] JOIN table2 ON conditional_expression …
|
||||
SELECT ad, yas FROM Tablo1 INNER JOIN Tablo2 ON Tablo1.ad = Tablo2.soyad;
|
||||
|
||||
-- OUTER JOIN
|
||||
-- Outer join iki tablodaki ortak kolon değerlerinin dışında kalanları kullanarak bir sonuç üretir.
|
||||
SELECT isci_num, isim, dept FROM Tablo1 LEFT OUTER JOIN Tablo2 ON Tablo1.id = Tablo2.isci_num;
|
||||
|
||||
-- ÇEKİRDEK FONKSİYONLAR
|
||||
COUNT -- Sayma
|
||||
AVG -- Ortalama
|
||||
ABS -- Mutlak değer
|
||||
SUM -- Toplam
|
||||
RANDOM -- Rastgele
|
||||
ROUND -- Yuvarlama
|
||||
MAX -- Maksimim
|
||||
MIN -- Minimum
|
||||
UPPER -- Büyük Harf
|
||||
LOWER -- Küçük Harf
|
||||
LENGTH -- Uzunluk
|
||||
CURRENT_TIMESTAMP -- Zaman
|
||||
|
||||
SELECT max(yas) FROM Table1;
|
||||
SELECT min(yas) FROM Table1;
|
||||
SELECT avg(yas) FROM Table1;
|
||||
SELECT * From Table1 WHERE yas ==18;
|
||||
SELECT sum(yas) FROM Table1;
|
||||
SELECT random() AS Random;
|
||||
SELECT upper(ad) FROM Table1;
|
||||
SELECT lower(ad) FROM Table1;
|
||||
SELECT ad, length(ad) FROM Table1;
|
||||
---
|
||||
language: SQL
|
||||
contributors:
|
||||
- ["Metin Yalçınkaya", "https://github.com/mtnylnky"]
|
||||
lang: tr-tr
|
||||
filename: learnsql-tr.sql
|
||||
---
|
||||
|
||||
|
||||
```sql
|
||||
-- Yorumlar iki tire ile başlar
|
||||
|
||||
-- KISITLAR
|
||||
Not null -- Bir kolon asla boş olamaz
|
||||
default -- Boş olan yerlere varsayılan bir değer atar
|
||||
unique -- Bir kolondaki tüm değerlerin farklı olması kısıtlaması
|
||||
primary key -- Bir tablodaki her veri için kimlik bilgisi niteliğindedir
|
||||
check -- Bir kolondaki değerlerin belli bir kısıtlamayı sağlamasını sağlar
|
||||
|
||||
-- Tablo oluşturulur
|
||||
CREATE TABLE tablo1 ();
|
||||
|
||||
-- Tabloyu içerisinde kolonlar ile oluşturma
|
||||
CREATE TABLE tablo1(id INTEGER PRIMARY KEY NOT NULL UNIQUE, ad TEXT, soyad TEXT, yas INTEGER);
|
||||
|
||||
-- TABLO varlığını kontrol eder
|
||||
.table
|
||||
|
||||
-- Veri tabanında olan bütün tabloları görüntüler.
|
||||
.schema
|
||||
|
||||
-- Satır ekle
|
||||
INSERT INTO tablo1 ( ad, soyad) VALUES ("Deger1","Deger2");
|
||||
|
||||
-- Veritabanında tablo üzerindeki verileri görüntüle
|
||||
-- Sadece 'ad' gibi sınırlı bir veri için
|
||||
SELECT ad FROM tablo1;
|
||||
-- Bütün veriler için
|
||||
SELECT * FROM tablo1;
|
||||
|
||||
-- Veri güncelleme
|
||||
UPDATE tablo1 SET ad = "deger1-2"; WHERE name = "Deger1";
|
||||
|
||||
-- Satır sil
|
||||
DELETE FROM tablo1 WHERE id = 1;
|
||||
DELETE FROM tablo1 WHERE ad = "Deger1" OR ad = "Deger2";
|
||||
|
||||
-- Tabloya sonradan kolon ekleme
|
||||
ALTER TABLE tablo1 ADD COLUMN email TEXT;
|
||||
|
||||
-- Tablodaki kolon adı değiştirme
|
||||
EXEC sp_rename ' tablo1.[ad]', Ad, 'COLUMN';
|
||||
|
||||
-- Tablo adı değiştirme
|
||||
ALTER TABLE table1 RENAME TO Table1;
|
||||
|
||||
-- Tabloyu silme
|
||||
DROP TABLE Table1;
|
||||
|
||||
-- BİR TABLOYU BAŞKA TABLO KULLANARAK DOLDURMAK
|
||||
INSERT INTO Tablo2 SELECT id,ad, soyad, email from Tablo1;
|
||||
|
||||
-- LIKE KOMUTU
|
||||
-- Belirli bir kritere göre arama yaparken kullanılır
|
||||
-- Adı 'A' ile başlayan veriler
|
||||
SELECT * FROM tablo1 WHERE adi LIKE "A%";
|
||||
-- İçinde 'A' olan veriler
|
||||
SELECT * FROM tablo1 WHERE adi LIKE "%A%";
|
||||
|
||||
-- LIMIT KOMUTU
|
||||
-- Gösterilen satır sayısını sınırlamak için
|
||||
SELECT * FROM Tablo1 LIMIT 6;
|
||||
-- Gösterilen satırları belirli bir noktadan başlamak üzere sınırlamak için
|
||||
SELECT * FROM Tablo1 LIMIT 6 OFFSET 3;
|
||||
|
||||
-- ORDER BY KOMUTU
|
||||
-- Herhangi bir kolona göre gösterilen değerleri azalan veya artan şekilde sıralamak için
|
||||
SELECT kolon FROM tablo1 WHERE yas ORDER BY column1, column2, .. columnN] [ASC | DESC];
|
||||
SELECT * FROM Tablo1 ORDER BY yas ASC
|
||||
SELECT * FROM Tablo1 ORDER BY yas DESC
|
||||
|
||||
-- DISTINCT ANAHTAR SÖZCÜĞÜ
|
||||
-- Bu anahtar sözcükle sadece farklı değerler gösterilir.
|
||||
SELECT DISTINCT yas FROM tablo1;
|
||||
|
||||
-- JOIN KOMUTU
|
||||
-- CROSS JOIN
|
||||
-- Cross join bir tablodaki her satırı ikinci tablodaki bir satır ile eşleştirmek için kulanılır.
|
||||
-- Eğer birinci tabloda x satır ikinci tabloda y satır varsa sonuçta x*y satır olur.
|
||||
SELECT ... FROM table1 CROSS JOIN table2 …
|
||||
SELECT ad, yas FROM Tablo1 CROSS JOIN Tablo2;
|
||||
|
||||
-- INNER JOIN
|
||||
-- Inner join iki tablodaki ortak kolon değerlerini kullanarak bir sonuç üretir.
|
||||
SELECT ... FROM table1 [INNER] JOIN table2 ON conditional_expression …
|
||||
SELECT ad, yas FROM Tablo1 INNER JOIN Tablo2 ON Tablo1.ad = Tablo2.soyad;
|
||||
|
||||
-- OUTER JOIN
|
||||
-- Outer join iki tablodaki ortak kolon değerlerinin dışında kalanları kullanarak bir sonuç üretir.
|
||||
SELECT isci_num, isim, dept FROM Tablo1 LEFT OUTER JOIN Tablo2 ON Tablo1.id = Tablo2.isci_num;
|
||||
|
||||
-- ÇEKİRDEK FONKSİYONLAR
|
||||
COUNT -- Sayma
|
||||
AVG -- Ortalama
|
||||
ABS -- Mutlak değer
|
||||
SUM -- Toplam
|
||||
RANDOM -- Rastgele
|
||||
ROUND -- Yuvarlama
|
||||
MAX -- Maksimim
|
||||
MIN -- Minimum
|
||||
UPPER -- Büyük Harf
|
||||
LOWER -- Küçük Harf
|
||||
LENGTH -- Uzunluk
|
||||
CURRENT_TIMESTAMP -- Zaman
|
||||
|
||||
SELECT max(yas) FROM Table1;
|
||||
SELECT min(yas) FROM Table1;
|
||||
SELECT avg(yas) FROM Table1;
|
||||
SELECT * From Table1 WHERE yas ==18;
|
||||
SELECT sum(yas) FROM Table1;
|
||||
SELECT random() AS Random;
|
||||
SELECT upper(ad) FROM Table1;
|
||||
SELECT lower(ad) FROM Table1;
|
||||
SELECT ad, length(ad) FROM Table1;
|
||||
```
|
@ -1,328 +1,328 @@
|
||||
---
|
||||
category: tool
|
||||
tool: git
|
||||
contributors:
|
||||
---
|
||||
category: tool
|
||||
tool: git
|
||||
contributors:
|
||||
- ["Jake Prather", "http://github.com/JakeHP"]
|
||||
- ["Vinh Nguyen", "https://twitter.com/vinhnx"]
|
||||
filename: LearnGit-vi.txt
|
||||
lang: vi-vn
|
||||
---
|
||||
|
||||
Git là một hệ quản lý mã nguồn và phiên bản phân tán (distributed version control and source code management system).
|
||||
|
||||
Nó làm được điều này là do một loạt các snapshot từ đề án của bạn, và nó hoạt động
|
||||
với các snapshot đó để cung cấp cho bạn với chức năng đến phiên bản và
|
||||
quản lý mã nguồn của bạn.
|
||||
|
||||
## Khái Niệm Versioning
|
||||
|
||||
### Version Control là gì?
|
||||
|
||||
Version Control là một hệ thống ghi lại những thay đổi ở một tập tin, hay một nhóm các tập tin, theo thời gian.
|
||||
|
||||
### So sánh giữa Centralized Versioning và Distributed Versioning
|
||||
|
||||
* Quản lý phiên bản tập trung (Centralized Versioning) tập trung vào việc đồng bộ hóa, theo dõi, và lưu trữ tập tin.
|
||||
* Quản lý phiên bản phân tán (Distributed Versioning) tập trung vào việc chia sẻ các thay đổi. Mỗi sự thay đổi có một mã định dạng (id) duy nhất.
|
||||
* Các hệ phân tán không có cấu trúc định sẵn. Bạn có thể thay đổi một kiểu SVN, hệ phân tán, với git.
|
||||
|
||||
[Thông tin thêm](http://git-scm.com/book/en/Getting-Started-About-Version-Control)
|
||||
|
||||
### Tại Sao Dùng Git?
|
||||
|
||||
* Có thể hoạt động offline.
|
||||
* Cộng tác với nhau rất dễ dàng!
|
||||
* Phân nhánh dễ dàng!
|
||||
* Trộn (Merging)
|
||||
* Git nhanh.
|
||||
* Git linh hoạt.
|
||||
|
||||
## Kiến Trúc Git
|
||||
|
||||
|
||||
### Repository
|
||||
|
||||
Một nhóm các tập tin, thư mục, các ghi chép trong quá khứ, commit, và heads. Tưởng tượng nó như là một cấu trúc dữ liệu mã nguồn,
|
||||
với thuộc tính mà một "nhân tố" mã nguồn cho bạn quyền truy cập đến lịch sử sửa đổi, và một số thứ khác.
|
||||
|
||||
Một git repository bao gồm thư mục .git & tree đang làm việc.
|
||||
|
||||
### Thư mục .git (thành phần của một repository)
|
||||
|
||||
Thư mục .git chứa tất cả các cấu hình, log, nhánh, HEAD, và hơn nữa.
|
||||
[Danh Sách Chi Tiết.](http://gitready.com/advanced/2009/03/23/whats-inside-your-git-directory.html)
|
||||
|
||||
### Tree Đang Làm (thành phần của một repository)
|
||||
|
||||
Đây cơ bản là các thư mục và tập tin trong repository của bạn. Nó thường được tham chiếu
|
||||
thư mục đang làm việc của bạn
|
||||
|
||||
### Chỉ mục (thành phần của một thư mục .git)
|
||||
|
||||
Chỉ mục của là một staging area trong git. Nó đơn giản là một lớp riêng biệt với tree đang làm việc của bạn
|
||||
từ Git repository. Điều này cho nhà phát triền nhiều lựa chọn hơn trong việc xem xét những gì được gửi đến Git
|
||||
repository.
|
||||
|
||||
### Commit
|
||||
|
||||
Một git commit là một snapshot của một nhóm các thay đổi, hoặc các thao tác Working Tree của bạn.
|
||||
Ví dụ, nếu bạn thêm 5 tập tin, và xóa 2 tập tin khác, những thay đổi này sẽ được chứa trong
|
||||
một commit (hoặc snapshot). Commit này có thể được đẩy đến các repo khác, hoặc không!
|
||||
|
||||
### Nhánh
|
||||
|
||||
Nhánh thực chất là một con trỏ đến commit mới nhất mà bạn vừa thực hiện. Khi bạn commit,
|
||||
con trỏ này sẽ cập nhật tự động và trỏ đến commit mới nhất.
|
||||
|
||||
### HEAD và head (thành phần của thư mục .git)
|
||||
|
||||
HEAD là một con trỏ đến branch hiện tại. Một repo chỉ có một HEAD *đang hoạt động*.
|
||||
head là một con trỏ đến bất kỳ commit nào. Một repo có thể có nhiều head.
|
||||
|
||||
### Các Tài Nguyên Mang Tính Khái Niệm
|
||||
|
||||
* [Git For Computer Scientists](http://eagain.net/articles/git-for-computer-scientists/)
|
||||
* [Git For Designers](http://hoth.entp.com/output/git_for_designers.html)
|
||||
|
||||
|
||||
## Các Lệnh
|
||||
|
||||
|
||||
### init
|
||||
|
||||
Tạo một repo Git rỗng. Các cài đặt, thông tin lưu trữ... của Git
|
||||
được lưu ở một thư mục tên là ".git".
|
||||
|
||||
```bash
|
||||
$ git init
|
||||
```
|
||||
|
||||
### config
|
||||
|
||||
Để chỉnh tùy chọn. Bất kể là cho repo, hay cho hệ thống, hay điều chỉnh
|
||||
toàn cục (global)
|
||||
|
||||
|
||||
|
||||
```bash
|
||||
# In Ra & Và Gán Một Số Biến Tùy Chỉnh Cơ Bản (Toàn cục - Global)
|
||||
$ git config --global user.email
|
||||
$ git config --global user.name
|
||||
|
||||
$ git config --global user.email "MyEmail@Zoho.com"
|
||||
$ git config --global user.name "My Name"
|
||||
```
|
||||
|
||||
[Tìm hiểu thêm về git config.](http://git-scm.com/docs/git-config)
|
||||
|
||||
### help
|
||||
|
||||
Để cho bạn lối truy cập nhanh đến một chỉ dẫn cực kỳ chi tiết của từng lệnh. Hoặc chỉ để
|
||||
nhắc bạn một số cú pháp.
|
||||
|
||||
```bash
|
||||
# Xem nhanh các lệnh có sẵn
|
||||
$ git help
|
||||
|
||||
# Xem tất các các lệnh
|
||||
$ git help -a
|
||||
|
||||
# Lệnh help riêng biệt - tài liệu người dùng
|
||||
# git help <command_here>
|
||||
$ git help add
|
||||
$ git help commit
|
||||
$ git help init
|
||||
```
|
||||
|
||||
### status
|
||||
|
||||
Để hiển thị sự khác nhau giữa tập tin index (cơ bản là repo đang làm việc) và HEAD commit
|
||||
hiện tại.
|
||||
|
||||
|
||||
```bash
|
||||
# Sẽ hiển thị nhánh, các tập tin chưa track (chưa commit), các thay đổi và những khác biệt khác
|
||||
$ git status
|
||||
|
||||
# Để xem các "tid bits" về git status
|
||||
$ git help status
|
||||
```
|
||||
|
||||
### add
|
||||
|
||||
Để thêm các tập vào tree/thư mục/repo hiện tại. Nếu bạn không `git add` các tập tin mới đến
|
||||
tree/thư mục hiện tại, chúng sẽ không được kèm theo trong các commit!
|
||||
|
||||
```bash
|
||||
# thêm một file vào thư mục hiện tại
|
||||
$ git add HelloWorld.java
|
||||
|
||||
# thêm một file vào một thư mục khác
|
||||
$ git add /path/to/file/HelloWorld.c
|
||||
|
||||
# Hỗ trợ Regular Expression!
|
||||
$ git add ./*.java
|
||||
```
|
||||
|
||||
### branch
|
||||
|
||||
Quản lý nhánh (branch). Bạn có thể xem, sửa, tạo, xóa các nhánh bằng cách dùng lệnh này.
|
||||
|
||||
```bash
|
||||
# liệt kê các branch đang có và ở remote
|
||||
$ git branch -a
|
||||
|
||||
# tạo branch mới
|
||||
$ git branch myNewBranch
|
||||
|
||||
# xóa một branch
|
||||
$ git branch -d myBranch
|
||||
|
||||
# đặt tên lại một branch
|
||||
# git branch -m <oldname> <newname>
|
||||
$ git branch -m myBranchName myNewBranchName
|
||||
|
||||
# chỉnh sửa diễn giải của một branch
|
||||
$ git branch myBranchName --edit-description
|
||||
```
|
||||
|
||||
### checkout
|
||||
|
||||
Cập nhật tất cả các file trong tree hiện tại để cho trùng khớp với phiên bản của index, hoặc tree cụ thể.
|
||||
|
||||
```bash
|
||||
# Checkout (chuyển) một repo - mặc định là nhánh master
|
||||
$ git checkout
|
||||
# Checkout một nhánh cụ thể
|
||||
$ git checkout branchName
|
||||
# Tạo một nhánh mới và chuyển đến nó, tương tự: "git branch <name>; git checkout <name>"
|
||||
$ git checkout -b newBranch
|
||||
```
|
||||
|
||||
### clone
|
||||
|
||||
Nhân bản, hoặc sao chép, một repo hiện có thành một thư mục mới. Nó cũng thêm
|
||||
các branch có remote-tracking cho mỗi branch trong một repo được nhân bản, mà
|
||||
cho phép bạn push đến một remote branch.
|
||||
|
||||
```bash
|
||||
# Nhân bản learnxinyminutes-docs
|
||||
$ git clone https://github.com/adambard/learnxinyminutes-docs.git
|
||||
```
|
||||
|
||||
### commit
|
||||
|
||||
Lưu trữ nội dung hiện tại của index trong một "commit" mới. Điều này cho phép tạo ra thay đổi và một ghi chú tạo ra bởi người dùng.
|
||||
|
||||
```bash
|
||||
# commit với một ghi chú
|
||||
$ git commit -m "Added multiplyNumbers() function to HelloWorld.c"
|
||||
```
|
||||
|
||||
### diff
|
||||
|
||||
Hiển thị sự khác biệt giữa một file trong thư mục hiện tại, index và commits.
|
||||
|
||||
```bash
|
||||
# Hiển thị sự khác biệt giữa thư mục hiện tại và index
|
||||
$ git diff
|
||||
|
||||
# Hiển thị khác biệt giữa index và commit mới nhất.
|
||||
$ git diff --cached
|
||||
|
||||
# Hiển thị khác biệt giữa thư mục đang làm việc và commit mới nhất
|
||||
$ git diff HEAD
|
||||
```
|
||||
|
||||
### grep
|
||||
|
||||
Cho phép bạn tìm kiếm nhanh một repo.
|
||||
|
||||
Các tinh chỉnh tùy chọn:
|
||||
|
||||
```bash
|
||||
# Cảm ơn Travis Jeffery vì những lệnh này
|
||||
# Đặt số của dòng được hiển thị trong kết quả tìm kiếm grep
|
||||
$ git config --global grep.lineNumber true
|
||||
|
||||
# Làm cho kết quả tìm kiếm dễ đọc hơn, bao gồm cả gom nhóm
|
||||
$ git config --global alias.g "grep --break --heading --line-number"
|
||||
```
|
||||
|
||||
```bash
|
||||
# Tìm "variableName" trong tất cả các file Java
|
||||
$ git grep 'variableName' -- '*.java'
|
||||
|
||||
# Tìm một dòng mà có chứa "arrayListName" và, "add" hoặc "remove"
|
||||
$ git grep -e 'arrayListName' --and \( -e add -e remove \)
|
||||
```
|
||||
|
||||
Google để xem thêm các ví dụ
|
||||
[Git Grep Ninja](http://travisjeffery.com/b/2012/02/search-a-git-repo-like-a-ninja)
|
||||
|
||||
### log
|
||||
|
||||
Hiển thị các commit đến repo.
|
||||
|
||||
```bash
|
||||
# Hiện tất cả các commit
|
||||
$ git log
|
||||
|
||||
# Hiện X commit
|
||||
$ git log -n 10
|
||||
|
||||
# Chỉ hiện các commit đã merge merge commits
|
||||
$ git log --merges
|
||||
```
|
||||
|
||||
### merge
|
||||
|
||||
"Trộn" các thay đổi từ commit bên ngoài vào trong nhánh hiện tại.
|
||||
|
||||
```bash
|
||||
# Merge branch cụ thể vào branch hiện tại.
|
||||
$ git merge branchName
|
||||
|
||||
# Luôn khởi tạo một merge commit khi trộn (merge)
|
||||
$ git merge --no-ff branchName
|
||||
```
|
||||
|
||||
### mv
|
||||
|
||||
Đặt lại tên hoặc di chuyển một file
|
||||
|
||||
```bash
|
||||
# Đặt lại tên một file
|
||||
$ git mv HelloWorld.c HelloNewWorld.c
|
||||
|
||||
# Di chuyển một file
|
||||
$ git mv HelloWorld.c ./new/path/HelloWorld.c
|
||||
|
||||
# Buộc đặt lại tên hoặc di chuyển
|
||||
# "existingFile" đã tồn tại trong thự mục, sẽ bị ghi đè
|
||||
$ git mv -f myFile existingFile
|
||||
```
|
||||
|
||||
### pull
|
||||
|
||||
Pull về từ một repo và merge nó vào branch khác.
|
||||
|
||||
```bash
|
||||
# Cập nhật repo local của bạn, bằng cách merge các thay đổi mới
|
||||
# từ remote "origin" và nhánh "master".
|
||||
# git pull <remote> <branch>
|
||||
# git pull => hoàn toàn mặc định như => git pull origin master
|
||||
$ git pull origin master
|
||||
|
||||
# Merge các thay đổi từ remote branch và rebase
|
||||
# các commit trong branch lên trên local repo, như sau: "git pull <remote> <branch>, git rebase <branch>"
|
||||
$ git pull origin master --rebase
|
||||
```
|
||||
|
||||
### push
|
||||
|
||||
push và merge các thay đổi từ một branch đến một remote & branch.
|
||||
|
||||
- ["Vinh Nguyen", "https://twitter.com/vinhnx"]
|
||||
filename: LearnGit-vi.txt
|
||||
lang: vi-vn
|
||||
---
|
||||
|
||||
Git là một hệ quản lý mã nguồn và phiên bản phân tán (distributed version control and source code management system).
|
||||
|
||||
Nó làm được điều này là do một loạt các snapshot từ đề án của bạn, và nó hoạt động
|
||||
với các snapshot đó để cung cấp cho bạn với chức năng đến phiên bản và
|
||||
quản lý mã nguồn của bạn.
|
||||
|
||||
## Khái Niệm Versioning
|
||||
|
||||
### Version Control là gì?
|
||||
|
||||
Version Control là một hệ thống ghi lại những thay đổi ở một tập tin, hay một nhóm các tập tin, theo thời gian.
|
||||
|
||||
### So sánh giữa Centralized Versioning và Distributed Versioning
|
||||
|
||||
* Quản lý phiên bản tập trung (Centralized Versioning) tập trung vào việc đồng bộ hóa, theo dõi, và lưu trữ tập tin.
|
||||
* Quản lý phiên bản phân tán (Distributed Versioning) tập trung vào việc chia sẻ các thay đổi. Mỗi sự thay đổi có một mã định dạng (id) duy nhất.
|
||||
* Các hệ phân tán không có cấu trúc định sẵn. Bạn có thể thay đổi một kiểu SVN, hệ phân tán, với git.
|
||||
|
||||
[Thông tin thêm](http://git-scm.com/book/en/Getting-Started-About-Version-Control)
|
||||
|
||||
### Tại Sao Dùng Git?
|
||||
|
||||
* Có thể hoạt động offline.
|
||||
* Cộng tác với nhau rất dễ dàng!
|
||||
* Phân nhánh dễ dàng!
|
||||
* Trộn (Merging)
|
||||
* Git nhanh.
|
||||
* Git linh hoạt.
|
||||
|
||||
## Kiến Trúc Git
|
||||
|
||||
|
||||
### Repository
|
||||
|
||||
Một nhóm các tập tin, thư mục, các ghi chép trong quá khứ, commit, và heads. Tưởng tượng nó như là một cấu trúc dữ liệu mã nguồn,
|
||||
với thuộc tính mà một "nhân tố" mã nguồn cho bạn quyền truy cập đến lịch sử sửa đổi, và một số thứ khác.
|
||||
|
||||
Một git repository bao gồm thư mục .git & tree đang làm việc.
|
||||
|
||||
### Thư mục .git (thành phần của một repository)
|
||||
|
||||
Thư mục .git chứa tất cả các cấu hình, log, nhánh, HEAD, và hơn nữa.
|
||||
[Danh Sách Chi Tiết.](http://gitready.com/advanced/2009/03/23/whats-inside-your-git-directory.html)
|
||||
|
||||
### Tree Đang Làm (thành phần của một repository)
|
||||
|
||||
Đây cơ bản là các thư mục và tập tin trong repository của bạn. Nó thường được tham chiếu
|
||||
thư mục đang làm việc của bạn
|
||||
|
||||
### Chỉ mục (thành phần của một thư mục .git)
|
||||
|
||||
Chỉ mục của là một staging area trong git. Nó đơn giản là một lớp riêng biệt với tree đang làm việc của bạn
|
||||
từ Git repository. Điều này cho nhà phát triền nhiều lựa chọn hơn trong việc xem xét những gì được gửi đến Git
|
||||
repository.
|
||||
|
||||
### Commit
|
||||
|
||||
Một git commit là một snapshot của một nhóm các thay đổi, hoặc các thao tác Working Tree của bạn.
|
||||
Ví dụ, nếu bạn thêm 5 tập tin, và xóa 2 tập tin khác, những thay đổi này sẽ được chứa trong
|
||||
một commit (hoặc snapshot). Commit này có thể được đẩy đến các repo khác, hoặc không!
|
||||
|
||||
### Nhánh
|
||||
|
||||
Nhánh thực chất là một con trỏ đến commit mới nhất mà bạn vừa thực hiện. Khi bạn commit,
|
||||
con trỏ này sẽ cập nhật tự động và trỏ đến commit mới nhất.
|
||||
|
||||
### HEAD và head (thành phần của thư mục .git)
|
||||
|
||||
HEAD là một con trỏ đến branch hiện tại. Một repo chỉ có một HEAD *đang hoạt động*.
|
||||
head là một con trỏ đến bất kỳ commit nào. Một repo có thể có nhiều head.
|
||||
|
||||
### Các Tài Nguyên Mang Tính Khái Niệm
|
||||
|
||||
* [Git For Computer Scientists](http://eagain.net/articles/git-for-computer-scientists/)
|
||||
* [Git For Designers](http://hoth.entp.com/output/git_for_designers.html)
|
||||
|
||||
|
||||
## Các Lệnh
|
||||
|
||||
|
||||
### init
|
||||
|
||||
Tạo một repo Git rỗng. Các cài đặt, thông tin lưu trữ... của Git
|
||||
được lưu ở một thư mục tên là ".git".
|
||||
|
||||
```bash
|
||||
$ git init
|
||||
```
|
||||
|
||||
### config
|
||||
|
||||
Để chỉnh tùy chọn. Bất kể là cho repo, hay cho hệ thống, hay điều chỉnh
|
||||
toàn cục (global)
|
||||
|
||||
|
||||
|
||||
```bash
|
||||
# In Ra & Và Gán Một Số Biến Tùy Chỉnh Cơ Bản (Toàn cục - Global)
|
||||
$ git config --global user.email
|
||||
$ git config --global user.name
|
||||
|
||||
$ git config --global user.email "MyEmail@Zoho.com"
|
||||
$ git config --global user.name "My Name"
|
||||
```
|
||||
|
||||
[Tìm hiểu thêm về git config.](http://git-scm.com/docs/git-config)
|
||||
|
||||
### help
|
||||
|
||||
Để cho bạn lối truy cập nhanh đến một chỉ dẫn cực kỳ chi tiết của từng lệnh. Hoặc chỉ để
|
||||
nhắc bạn một số cú pháp.
|
||||
|
||||
```bash
|
||||
# Xem nhanh các lệnh có sẵn
|
||||
$ git help
|
||||
|
||||
# Xem tất các các lệnh
|
||||
$ git help -a
|
||||
|
||||
# Lệnh help riêng biệt - tài liệu người dùng
|
||||
# git help <command_here>
|
||||
$ git help add
|
||||
$ git help commit
|
||||
$ git help init
|
||||
```
|
||||
|
||||
### status
|
||||
|
||||
Để hiển thị sự khác nhau giữa tập tin index (cơ bản là repo đang làm việc) và HEAD commit
|
||||
hiện tại.
|
||||
|
||||
|
||||
```bash
|
||||
# Sẽ hiển thị nhánh, các tập tin chưa track (chưa commit), các thay đổi và những khác biệt khác
|
||||
$ git status
|
||||
|
||||
# Để xem các "tid bits" về git status
|
||||
$ git help status
|
||||
```
|
||||
|
||||
### add
|
||||
|
||||
Để thêm các tập vào tree/thư mục/repo hiện tại. Nếu bạn không `git add` các tập tin mới đến
|
||||
tree/thư mục hiện tại, chúng sẽ không được kèm theo trong các commit!
|
||||
|
||||
```bash
|
||||
# thêm một file vào thư mục hiện tại
|
||||
$ git add HelloWorld.java
|
||||
|
||||
# thêm một file vào một thư mục khác
|
||||
$ git add /path/to/file/HelloWorld.c
|
||||
|
||||
# Hỗ trợ Regular Expression!
|
||||
$ git add ./*.java
|
||||
```
|
||||
|
||||
### branch
|
||||
|
||||
Quản lý nhánh (branch). Bạn có thể xem, sửa, tạo, xóa các nhánh bằng cách dùng lệnh này.
|
||||
|
||||
```bash
|
||||
# liệt kê các branch đang có và ở remote
|
||||
$ git branch -a
|
||||
|
||||
# tạo branch mới
|
||||
$ git branch myNewBranch
|
||||
|
||||
# xóa một branch
|
||||
$ git branch -d myBranch
|
||||
|
||||
# đặt tên lại một branch
|
||||
# git branch -m <oldname> <newname>
|
||||
$ git branch -m myBranchName myNewBranchName
|
||||
|
||||
# chỉnh sửa diễn giải của một branch
|
||||
$ git branch myBranchName --edit-description
|
||||
```
|
||||
|
||||
### checkout
|
||||
|
||||
Cập nhật tất cả các file trong tree hiện tại để cho trùng khớp với phiên bản của index, hoặc tree cụ thể.
|
||||
|
||||
```bash
|
||||
# Checkout (chuyển) một repo - mặc định là nhánh master
|
||||
$ git checkout
|
||||
# Checkout một nhánh cụ thể
|
||||
$ git checkout branchName
|
||||
# Tạo một nhánh mới và chuyển đến nó, tương tự: "git branch <name>; git checkout <name>"
|
||||
$ git checkout -b newBranch
|
||||
```
|
||||
|
||||
### clone
|
||||
|
||||
Nhân bản, hoặc sao chép, một repo hiện có thành một thư mục mới. Nó cũng thêm
|
||||
các branch có remote-tracking cho mỗi branch trong một repo được nhân bản, mà
|
||||
cho phép bạn push đến một remote branch.
|
||||
|
||||
```bash
|
||||
# Nhân bản learnxinyminutes-docs
|
||||
$ git clone https://github.com/adambard/learnxinyminutes-docs.git
|
||||
```
|
||||
|
||||
### commit
|
||||
|
||||
Lưu trữ nội dung hiện tại của index trong một "commit" mới. Điều này cho phép tạo ra thay đổi và một ghi chú tạo ra bởi người dùng.
|
||||
|
||||
```bash
|
||||
# commit với một ghi chú
|
||||
$ git commit -m "Added multiplyNumbers() function to HelloWorld.c"
|
||||
```
|
||||
|
||||
### diff
|
||||
|
||||
Hiển thị sự khác biệt giữa một file trong thư mục hiện tại, index và commits.
|
||||
|
||||
```bash
|
||||
# Hiển thị sự khác biệt giữa thư mục hiện tại và index
|
||||
$ git diff
|
||||
|
||||
# Hiển thị khác biệt giữa index và commit mới nhất.
|
||||
$ git diff --cached
|
||||
|
||||
# Hiển thị khác biệt giữa thư mục đang làm việc và commit mới nhất
|
||||
$ git diff HEAD
|
||||
```
|
||||
|
||||
### grep
|
||||
|
||||
Cho phép bạn tìm kiếm nhanh một repo.
|
||||
|
||||
Các tinh chỉnh tùy chọn:
|
||||
|
||||
```bash
|
||||
# Cảm ơn Travis Jeffery vì những lệnh này
|
||||
# Đặt số của dòng được hiển thị trong kết quả tìm kiếm grep
|
||||
$ git config --global grep.lineNumber true
|
||||
|
||||
# Làm cho kết quả tìm kiếm dễ đọc hơn, bao gồm cả gom nhóm
|
||||
$ git config --global alias.g "grep --break --heading --line-number"
|
||||
```
|
||||
|
||||
```bash
|
||||
# Tìm "variableName" trong tất cả các file Java
|
||||
$ git grep 'variableName' -- '*.java'
|
||||
|
||||
# Tìm một dòng mà có chứa "arrayListName" và, "add" hoặc "remove"
|
||||
$ git grep -e 'arrayListName' --and \( -e add -e remove \)
|
||||
```
|
||||
|
||||
Google để xem thêm các ví dụ
|
||||
[Git Grep Ninja](http://travisjeffery.com/b/2012/02/search-a-git-repo-like-a-ninja)
|
||||
|
||||
### log
|
||||
|
||||
Hiển thị các commit đến repo.
|
||||
|
||||
```bash
|
||||
# Hiện tất cả các commit
|
||||
$ git log
|
||||
|
||||
# Hiện X commit
|
||||
$ git log -n 10
|
||||
|
||||
# Chỉ hiện các commit đã merge merge commits
|
||||
$ git log --merges
|
||||
```
|
||||
|
||||
### merge
|
||||
|
||||
"Trộn" các thay đổi từ commit bên ngoài vào trong nhánh hiện tại.
|
||||
|
||||
```bash
|
||||
# Merge branch cụ thể vào branch hiện tại.
|
||||
$ git merge branchName
|
||||
|
||||
# Luôn khởi tạo một merge commit khi trộn (merge)
|
||||
$ git merge --no-ff branchName
|
||||
```
|
||||
|
||||
### mv
|
||||
|
||||
Đặt lại tên hoặc di chuyển một file
|
||||
|
||||
```bash
|
||||
# Đặt lại tên một file
|
||||
$ git mv HelloWorld.c HelloNewWorld.c
|
||||
|
||||
# Di chuyển một file
|
||||
$ git mv HelloWorld.c ./new/path/HelloWorld.c
|
||||
|
||||
# Buộc đặt lại tên hoặc di chuyển
|
||||
# "existingFile" đã tồn tại trong thự mục, sẽ bị ghi đè
|
||||
$ git mv -f myFile existingFile
|
||||
```
|
||||
|
||||
### pull
|
||||
|
||||
Pull về từ một repo và merge nó vào branch khác.
|
||||
|
||||
```bash
|
||||
# Cập nhật repo local của bạn, bằng cách merge các thay đổi mới
|
||||
# từ remote "origin" và nhánh "master".
|
||||
# git pull <remote> <branch>
|
||||
# git pull => hoàn toàn mặc định như => git pull origin master
|
||||
$ git pull origin master
|
||||
|
||||
# Merge các thay đổi từ remote branch và rebase
|
||||
# các commit trong branch lên trên local repo, như sau: "git pull <remote> <branch>, git rebase <branch>"
|
||||
$ git pull origin master --rebase
|
||||
```
|
||||
|
||||
### push
|
||||
|
||||
push và merge các thay đổi từ một branch đến một remote & branch.
|
||||
|
||||
```bash
|
||||
# Push và merge các thay đổi từ một repo local đến một
|
||||
# remote có tên là "origin" và nhánh "master".
|
||||
@ -334,68 +334,68 @@ $ git push origin master
|
||||
$ git push -u origin master
|
||||
# Từ lúc này, bất cứ khi nào bạn muốn push từ cùng một nhánh local đó, sử dụng lối tắt:
|
||||
$ git push
|
||||
```
|
||||
|
||||
### rebase (thận trọng)
|
||||
|
||||
Lấy tất cả các thay đổi mà đã được commit trên một nhánh, và replay (?) chúng trên một nhánh khác.
|
||||
*Không rebase các commit mà bạn đã push đến một repo công khai*.
|
||||
|
||||
```bash
|
||||
# Rebase experimentBranch lên master
|
||||
# git rebase <basebranch> <topicbranch>
|
||||
$ git rebase master experimentBranch
|
||||
```
|
||||
|
||||
[Đọc Thêm.](http://git-scm.com/book/en/Git-Branching-Rebasing)
|
||||
|
||||
### reset (thận trọng)
|
||||
|
||||
Thiết lập lạo HEAD hiện tại đến một trạng thái cụ thể. Điều này cho phép bạn làm lại các merges,
|
||||
pulls, commits, thêm, and hơn nữa. Nó là một lệnh hay nhưng cũng nguy hiểm nếu bạn không
|
||||
biết mình đang làm gì.
|
||||
|
||||
```bash
|
||||
# Thiết lập lại staging area, để trùng với commit mới nhất (để thư mục không thay đổi)
|
||||
$ git reset
|
||||
|
||||
# Thiết lập lại staging area, để trùng với commit mới nhất, và ghi đè lên thư mục hiện tại
|
||||
$ git reset --hard
|
||||
|
||||
# Di chuyển nhánh hiện tại đến một commit cụ thể (để thư mục không thay đổi)
|
||||
# tất cả thay đổi vẫn duy trì trong thư mục.
|
||||
$ git reset 31f2bb1
|
||||
|
||||
# Di chuyển nhánh hiện tại lùi về một commit cụ thể
|
||||
# và làm cho thư mục hiện tại trùng (xóa các thay đổi chưa được commit và tất cả các commit
|
||||
# sau một commit cụ thể).
|
||||
$ git reset --hard 31f2bb1
|
||||
```
|
||||
|
||||
### rm
|
||||
|
||||
Ngược lại với git add, git rm xóa file từ tree đang làm việc.
|
||||
|
||||
```bash
|
||||
# xóa HelloWorld.c
|
||||
$ git rm HelloWorld.c
|
||||
|
||||
# Xóa file từ thư mục khác
|
||||
$ git rm /pather/to/the/file/HelloWorld.c
|
||||
```
|
||||
|
||||
## Thông tin thêm
|
||||
|
||||
* [tryGit - A fun interactive way to learn Git.](http://try.github.io/levels/1/challenges/1)
|
||||
|
||||
* [git-scm - Video Tutorials](http://git-scm.com/videos)
|
||||
|
||||
* [git-scm - Documentation](http://git-scm.com/docs)
|
||||
|
||||
* [Atlassian Git - Tutorials & Workflows](https://www.atlassian.com/git/)
|
||||
|
||||
* [SalesForce Cheat Sheet](https://na1.salesforce.com/help/doc/en/salesforce_git_developer_cheatsheet.pdf)
|
||||
|
||||
* [Git - the simple guide](http://rogerdudler.github.io/git-guide/index.html)
|
||||
|
||||
```
|
||||
|
||||
### rebase (thận trọng)
|
||||
|
||||
Lấy tất cả các thay đổi mà đã được commit trên một nhánh, và replay (?) chúng trên một nhánh khác.
|
||||
*Không rebase các commit mà bạn đã push đến một repo công khai*.
|
||||
|
||||
```bash
|
||||
# Rebase experimentBranch lên master
|
||||
# git rebase <basebranch> <topicbranch>
|
||||
$ git rebase master experimentBranch
|
||||
```
|
||||
|
||||
[Đọc Thêm.](http://git-scm.com/book/en/Git-Branching-Rebasing)
|
||||
|
||||
### reset (thận trọng)
|
||||
|
||||
Thiết lập lạo HEAD hiện tại đến một trạng thái cụ thể. Điều này cho phép bạn làm lại các merges,
|
||||
pulls, commits, thêm, and hơn nữa. Nó là một lệnh hay nhưng cũng nguy hiểm nếu bạn không
|
||||
biết mình đang làm gì.
|
||||
|
||||
```bash
|
||||
# Thiết lập lại staging area, để trùng với commit mới nhất (để thư mục không thay đổi)
|
||||
$ git reset
|
||||
|
||||
# Thiết lập lại staging area, để trùng với commit mới nhất, và ghi đè lên thư mục hiện tại
|
||||
$ git reset --hard
|
||||
|
||||
# Di chuyển nhánh hiện tại đến một commit cụ thể (để thư mục không thay đổi)
|
||||
# tất cả thay đổi vẫn duy trì trong thư mục.
|
||||
$ git reset 31f2bb1
|
||||
|
||||
# Di chuyển nhánh hiện tại lùi về một commit cụ thể
|
||||
# và làm cho thư mục hiện tại trùng (xóa các thay đổi chưa được commit và tất cả các commit
|
||||
# sau một commit cụ thể).
|
||||
$ git reset --hard 31f2bb1
|
||||
```
|
||||
|
||||
### rm
|
||||
|
||||
Ngược lại với git add, git rm xóa file từ tree đang làm việc.
|
||||
|
||||
```bash
|
||||
# xóa HelloWorld.c
|
||||
$ git rm HelloWorld.c
|
||||
|
||||
# Xóa file từ thư mục khác
|
||||
$ git rm /pather/to/the/file/HelloWorld.c
|
||||
```
|
||||
|
||||
## Thông tin thêm
|
||||
|
||||
* [tryGit - A fun interactive way to learn Git.](http://try.github.io/levels/1/challenges/1)
|
||||
|
||||
* [git-scm - Video Tutorials](http://git-scm.com/videos)
|
||||
|
||||
* [git-scm - Documentation](http://git-scm.com/docs)
|
||||
|
||||
* [Atlassian Git - Tutorials & Workflows](https://www.atlassian.com/git/)
|
||||
|
||||
* [SalesForce Cheat Sheet](https://na1.salesforce.com/help/doc/en/salesforce_git_developer_cheatsheet.pdf)
|
||||
|
||||
* [Git - the simple guide](http://rogerdudler.github.io/git-guide/index.html)
|
||||
|
||||
|
||||
|
@ -1,316 +1,316 @@
|
||||
---
|
||||
language: Objective-C
|
||||
contributors:
|
||||
- ["Eugene Yagrushkin", "www.about.me/yagrushkin"]
|
||||
- ["Yannick Loriot", "https://github.com/YannickL"]
|
||||
lang: vi-vn
|
||||
filename: LearnObjectiveC-vi.m
|
||||
---
|
||||
|
||||
Objective-C là ngôn ngữ lập trình chính được sử dụng bởi Apple cho các hệ điều hành macOS, iOS và các framework tương ứng của họ, Cocoa và Cocoa Touch.
|
||||
Nó là một ngôn ngữ lập trình mục đích tổng quát, hướng đối tượng có bổ sung thêm kiểu truyền thông điệp giống Smalltalk vào ngôn ngữ lập trình C.
|
||||
|
||||
```objective-c
|
||||
// Chú thích dòng đơn bắt đầu với //
|
||||
|
||||
/*
|
||||
Chú thích đa dòng trông như thế này.
|
||||
*/
|
||||
|
||||
// Nhập các headers của framework Foundation với cú pháp #import
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "MyClass.h"
|
||||
|
||||
// Đầu vào chương trình của bạn là một hàm gọi là
|
||||
// main với một kiểu trả về kiểu integer.
|
||||
int main (int argc, const char * argv[])
|
||||
{
|
||||
// Tạo một autorelease pool để quản lý bộ nhớ vào chương trình
|
||||
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
// Sử dụng hàm NSLog() để in ra các dòng lệnh vào console
|
||||
NSLog(@"Hello World!"); // Print the string "Hello World!"
|
||||
|
||||
///////////////////////////////////////
|
||||
// Kiểu & Biến (Types & Variables)
|
||||
///////////////////////////////////////
|
||||
|
||||
// Khai báo số nguyên
|
||||
int myPrimitive1 = 1;
|
||||
long myPrimitive2 = 234554664565;
|
||||
|
||||
// Khai báo đối tượng
|
||||
// Đặt dấu nháy * vào trước tên biến cho khai báo đối tượng strong
|
||||
MyClass *myObject1 = nil; // Strong
|
||||
id myObject2 = nil; // Weak
|
||||
// %@ là một đối tượng
|
||||
// 'miêu tả' ('desciption') là thông lệ để trình bày giá trị của các Đối tượng
|
||||
NSLog(@"%@ và %@", myObject1, [myObject2 description]); // In ra "(null) và (null)"
|
||||
|
||||
// Chuỗi
|
||||
NSString *worldString = @"World";
|
||||
NSLog(@"Hello %@!", worldString); // In ra "Hello World!"
|
||||
|
||||
// Ký tự literals
|
||||
NSNumber *theLetterZNumber = @'Z';
|
||||
char theLetterZ = [theLetterZNumber charValue];
|
||||
NSLog(@"%c", theLetterZ);
|
||||
|
||||
// Số nguyên literals
|
||||
NSNumber *fortyTwoNumber = @42;
|
||||
int fortyTwo = [fortyTwoNumber intValue];
|
||||
NSLog(@"%i", fortyTwo);
|
||||
|
||||
NSNumber *fortyTwoUnsignedNumber = @42U;
|
||||
unsigned int fortyTwoUnsigned = [fortyTwoUnsignedNumber unsignedIntValue];
|
||||
NSLog(@"%u", fortyTwoUnsigned);
|
||||
|
||||
NSNumber *fortyTwoShortNumber = [NSNumber numberWithShort:42];
|
||||
short fortyTwoShort = [fortyTwoShortNumber shortValue];
|
||||
NSLog(@"%hi", fortyTwoShort);
|
||||
|
||||
NSNumber *fortyTwoLongNumber = @42L;
|
||||
long fortyTwoLong = [fortyTwoLongNumber longValue];
|
||||
NSLog(@"%li", fortyTwoLong);
|
||||
|
||||
// Dấu phẩy động (floating point) literals
|
||||
NSNumber *piFloatNumber = @3.141592654F;
|
||||
float piFloat = [piFloatNumber floatValue];
|
||||
NSLog(@"%f", piFloat);
|
||||
|
||||
NSNumber *piDoubleNumber = @3.1415926535;
|
||||
double piDouble = [piDoubleNumber doubleValue];
|
||||
NSLog(@"%f", piDouble);
|
||||
|
||||
// BOOL literals
|
||||
NSNumber *yesNumber = @YES;
|
||||
NSNumber *noNumber = @NO;
|
||||
|
||||
// Đối tượng Mảng
|
||||
NSArray *anArray = @[@1, @2, @3, @4];
|
||||
NSNumber *thirdNumber = anArray[2];
|
||||
NSLog(@"Third number = %@", thirdNumber); // In ra "Third number = 3"
|
||||
|
||||
// Đối tượng Từ điển
|
||||
NSDictionary *aDictionary = @{ @"key1" : @"value1", @"key2" : @"value2" };
|
||||
NSObject *valueObject = aDictionary[@"A Key"];
|
||||
NSLog(@"Đối tượng = %@", valueObject); // In ra "Object = (null)"
|
||||
|
||||
///////////////////////////////////////
|
||||
// Toán Tử (Operators)
|
||||
///////////////////////////////////////
|
||||
|
||||
// Các toán tử cũng hoạt động giống như ngôn ngữ C
|
||||
// Ví dụ:
|
||||
2 + 5; // => 7
|
||||
4.2f + 5.1f; // => 9.3f
|
||||
3 == 2; // => 0 (NO)
|
||||
3 != 2; // => 1 (YES)
|
||||
1 && 1; // => 1 (Logical and)
|
||||
0 || 1; // => 1 (Logical or)
|
||||
~0x0F; // => 0xF0 (bitwise negation)
|
||||
0x0F & 0xF0; // => 0x00 (bitwise AND)
|
||||
0x01 << 1; // => 0x02 (bitwise dịch trái (bởi 1))
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// Cấu Trúc Điều Khiển (Controls Structures)
|
||||
/////////////////////////////////////////////
|
||||
|
||||
// Câu lệnh If-Else
|
||||
if (NO)
|
||||
{
|
||||
NSLog(@"I am never run");
|
||||
} else if (0)
|
||||
{
|
||||
NSLog(@"I am also never run");
|
||||
} else
|
||||
{
|
||||
NSLog(@"I print");
|
||||
}
|
||||
|
||||
// Câu lệnh Switch
|
||||
switch (2)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
NSLog(@"I am never run");
|
||||
} break;
|
||||
case 1:
|
||||
{
|
||||
NSLog(@"I am also never run");
|
||||
} break;
|
||||
default:
|
||||
{
|
||||
NSLog(@"I print");
|
||||
} break;
|
||||
}
|
||||
|
||||
// Câu lệnh vòng lặp While
|
||||
int ii = 0;
|
||||
while (ii < 4)
|
||||
{
|
||||
NSLog(@"%d,", ii++); // ii++ tăng dần, sau khi sử dụng giá trị của nó.
|
||||
} // => in ra "0,"
|
||||
// "1,"
|
||||
// "2,"
|
||||
// "3,"
|
||||
|
||||
// Câu lệnh vòng lặp For
|
||||
int jj;
|
||||
for (jj=0; jj < 4; jj++)
|
||||
{
|
||||
NSLog(@"%d,", jj);
|
||||
} // => in ra "0,"
|
||||
// "1,"
|
||||
// "2,"
|
||||
// "3,"
|
||||
|
||||
// Câu lệnh Foreach
|
||||
NSArray *values = @[@0, @1, @2, @3];
|
||||
for (NSNumber *value in values)
|
||||
{
|
||||
NSLog(@"%@,", value);
|
||||
} // => in ra "0,"
|
||||
// "1,"
|
||||
// "2,"
|
||||
// "3,"
|
||||
|
||||
// Câu lệnh Try-Catch-Finally
|
||||
@try
|
||||
{
|
||||
// Your statements here
|
||||
@throw [NSException exceptionWithName:@"FileNotFoundException"
|
||||
reason:@"Không Tìm Thấy Tập Tin trên Hệ Thống" userInfo:nil];
|
||||
} @catch (NSException * e)
|
||||
{
|
||||
NSLog(@"Exception: %@", e);
|
||||
} @finally
|
||||
{
|
||||
NSLog(@"Finally");
|
||||
} // => in ra "Exception: Không Tìm Thấy Tập Tin trên Hệ Thống"
|
||||
// "Finally"
|
||||
|
||||
///////////////////////////////////////
|
||||
// Đối Tượng (Objects)
|
||||
///////////////////////////////////////
|
||||
|
||||
// Tạo một thực thể đối tượng bằng cách phân vùng nhớ và khởi tạo đối tượng đó.
|
||||
// Một đối tượng sẽ không thật sự hoạt động cho đến khi cả 2 bước alloc] init] được hoàn thành
|
||||
MyClass *myObject = [[MyClass alloc] init];
|
||||
|
||||
// Mô hình lập trình hướng đối tượng của Objective-C dựa trên việc truyền thông điệp (message)
|
||||
// và các thực thể đối tượng với nhau.
|
||||
// Trong Objective-C một đối tượng không đơn thuần gọi phương thức; nó truyền thông điệp.
|
||||
[myObject instanceMethodWithParameter:@"Steve Jobs"];
|
||||
|
||||
// Dọn dẹp vùng nhớ mà bạn đã dùng ở chương trình
|
||||
[pool drain];
|
||||
|
||||
// Kết thúc chương trình
|
||||
return 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////
|
||||
// Lớp và Hàm (Classes & Functions)
|
||||
///////////////////////////////////////
|
||||
|
||||
// Khai báo lớp của bạn ở một tập tin header (MyClass.h):
|
||||
// Cú pháp Khai Báo Lớp:
|
||||
// @interface ClassName : ParentClassName <ImplementedProtocols>
|
||||
// {
|
||||
// Khai báo biến thành viên;
|
||||
// }
|
||||
// -/+ (type) Khai báo method;
|
||||
// @end
|
||||
@interface MyClass : NSObject <MyProtocol>
|
||||
{
|
||||
int count;
|
||||
id data;
|
||||
NSString *name;
|
||||
}
|
||||
// Ký hiệu (notation) tiện ích để tự động khởi tạo public getter và setter
|
||||
@property int count;
|
||||
@property (copy) NSString *name; // Sao chép đối tượng trong quá trình gán.
|
||||
@property (readonly) id data; // Chỉ khai báo phương thức getter.
|
||||
|
||||
// Phương thức
|
||||
+/- (return type)methodSignature:(Parameter Type *)parameterName;
|
||||
|
||||
// dấu '+' cho phương thức lớp
|
||||
+ (NSString *)classMethod;
|
||||
|
||||
// dấu '-' cho phương thức thực thể
|
||||
- (NSString *)instanceMethodWithParameter:(NSString *)string;
|
||||
- (NSNumber *)methodAParameterAsString:(NSString*)string andAParameterAsNumber:(NSNumber *)number;
|
||||
|
||||
@end
|
||||
|
||||
// Thực thi các phương thức trong một tập tin thực thi (MyClass.m):
|
||||
|
||||
@implementation MyClass
|
||||
|
||||
// Gọi khi đối tượng được release
|
||||
- (void)dealloc
|
||||
{
|
||||
}
|
||||
|
||||
// Phương thức khởi tạo (Constructors) là một cách để tạo các lớp
|
||||
// Đây là phương thức khởi tạo mặc định được gọi khi đối tượng được khởi tạo
|
||||
- (id)init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
self.count = 1;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (NSString *)classMethod
|
||||
{
|
||||
return [[self alloc] init];
|
||||
}
|
||||
|
||||
- (NSString *)instanceMethodWithParameter:(NSString *)string
|
||||
{
|
||||
return @"New string";
|
||||
}
|
||||
|
||||
- (NSNumber *)methodAParameterAsString:(NSString*)string andAParameterAsNumber:(NSNumber *)number
|
||||
{
|
||||
return @42;
|
||||
}
|
||||
|
||||
// Các phương thức được khai báo vào MyProtocol
|
||||
- (void)myProtocolMethod
|
||||
{
|
||||
// câu lệnh
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/*
|
||||
* Một protocol khai báo các phương thức mà có thể thực thi bởi bất kỳ lớp nào.
|
||||
* Các protocol chính chúng không phải là các lớp. Chúng chỉ đơn giản là định ra giao diện (interface)
|
||||
* mà các đối tượng khác có trách nhiệm sẽ thực thi.
|
||||
*/
|
||||
@protocol MyProtocol
|
||||
- (void)myProtocolMethod;
|
||||
@end
|
||||
|
||||
|
||||
|
||||
```
|
||||
## Xem Thêm
|
||||
|
||||
+ [Wikipedia Objective-C](http://en.wikipedia.org/wiki/Objective-C)
|
||||
|
||||
+ Apple Docs':
|
||||
+ [Learning Objective-C](http://developer.apple.com/library/ios/referencelibrary/GettingStarted/Learning_Objective-C_A_Primer/)
|
||||
|
||||
+ [Programming With Objective-C](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Introduction/Introduction.html)
|
||||
|
||||
+ [Object-Oriented Programming with Objective-C](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/OOP_ObjC/Introduction/Introduction.html#//apple_ref/doc/uid/TP40005149)
|
||||
|
||||
+ [Coding Guidelines for Cocoa](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html)
|
||||
|
||||
+ [iOS For High School Students: Getting Started](http://www.raywenderlich.com/5600/ios-for-high-school-students-getting-started)
|
||||
---
|
||||
language: Objective-C
|
||||
contributors:
|
||||
- ["Eugene Yagrushkin", "www.about.me/yagrushkin"]
|
||||
- ["Yannick Loriot", "https://github.com/YannickL"]
|
||||
lang: vi-vn
|
||||
filename: LearnObjectiveC-vi.m
|
||||
---
|
||||
|
||||
Objective-C là ngôn ngữ lập trình chính được sử dụng bởi Apple cho các hệ điều hành macOS, iOS và các framework tương ứng của họ, Cocoa và Cocoa Touch.
|
||||
Nó là một ngôn ngữ lập trình mục đích tổng quát, hướng đối tượng có bổ sung thêm kiểu truyền thông điệp giống Smalltalk vào ngôn ngữ lập trình C.
|
||||
|
||||
```objective-c
|
||||
// Chú thích dòng đơn bắt đầu với //
|
||||
|
||||
/*
|
||||
Chú thích đa dòng trông như thế này.
|
||||
*/
|
||||
|
||||
// Nhập các headers của framework Foundation với cú pháp #import
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "MyClass.h"
|
||||
|
||||
// Đầu vào chương trình của bạn là một hàm gọi là
|
||||
// main với một kiểu trả về kiểu integer.
|
||||
int main (int argc, const char * argv[])
|
||||
{
|
||||
// Tạo một autorelease pool để quản lý bộ nhớ vào chương trình
|
||||
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
// Sử dụng hàm NSLog() để in ra các dòng lệnh vào console
|
||||
NSLog(@"Hello World!"); // Print the string "Hello World!"
|
||||
|
||||
///////////////////////////////////////
|
||||
// Kiểu & Biến (Types & Variables)
|
||||
///////////////////////////////////////
|
||||
|
||||
// Khai báo số nguyên
|
||||
int myPrimitive1 = 1;
|
||||
long myPrimitive2 = 234554664565;
|
||||
|
||||
// Khai báo đối tượng
|
||||
// Đặt dấu nháy * vào trước tên biến cho khai báo đối tượng strong
|
||||
MyClass *myObject1 = nil; // Strong
|
||||
id myObject2 = nil; // Weak
|
||||
// %@ là một đối tượng
|
||||
// 'miêu tả' ('desciption') là thông lệ để trình bày giá trị của các Đối tượng
|
||||
NSLog(@"%@ và %@", myObject1, [myObject2 description]); // In ra "(null) và (null)"
|
||||
|
||||
// Chuỗi
|
||||
NSString *worldString = @"World";
|
||||
NSLog(@"Hello %@!", worldString); // In ra "Hello World!"
|
||||
|
||||
// Ký tự literals
|
||||
NSNumber *theLetterZNumber = @'Z';
|
||||
char theLetterZ = [theLetterZNumber charValue];
|
||||
NSLog(@"%c", theLetterZ);
|
||||
|
||||
// Số nguyên literals
|
||||
NSNumber *fortyTwoNumber = @42;
|
||||
int fortyTwo = [fortyTwoNumber intValue];
|
||||
NSLog(@"%i", fortyTwo);
|
||||
|
||||
NSNumber *fortyTwoUnsignedNumber = @42U;
|
||||
unsigned int fortyTwoUnsigned = [fortyTwoUnsignedNumber unsignedIntValue];
|
||||
NSLog(@"%u", fortyTwoUnsigned);
|
||||
|
||||
NSNumber *fortyTwoShortNumber = [NSNumber numberWithShort:42];
|
||||
short fortyTwoShort = [fortyTwoShortNumber shortValue];
|
||||
NSLog(@"%hi", fortyTwoShort);
|
||||
|
||||
NSNumber *fortyTwoLongNumber = @42L;
|
||||
long fortyTwoLong = [fortyTwoLongNumber longValue];
|
||||
NSLog(@"%li", fortyTwoLong);
|
||||
|
||||
// Dấu phẩy động (floating point) literals
|
||||
NSNumber *piFloatNumber = @3.141592654F;
|
||||
float piFloat = [piFloatNumber floatValue];
|
||||
NSLog(@"%f", piFloat);
|
||||
|
||||
NSNumber *piDoubleNumber = @3.1415926535;
|
||||
double piDouble = [piDoubleNumber doubleValue];
|
||||
NSLog(@"%f", piDouble);
|
||||
|
||||
// BOOL literals
|
||||
NSNumber *yesNumber = @YES;
|
||||
NSNumber *noNumber = @NO;
|
||||
|
||||
// Đối tượng Mảng
|
||||
NSArray *anArray = @[@1, @2, @3, @4];
|
||||
NSNumber *thirdNumber = anArray[2];
|
||||
NSLog(@"Third number = %@", thirdNumber); // In ra "Third number = 3"
|
||||
|
||||
// Đối tượng Từ điển
|
||||
NSDictionary *aDictionary = @{ @"key1" : @"value1", @"key2" : @"value2" };
|
||||
NSObject *valueObject = aDictionary[@"A Key"];
|
||||
NSLog(@"Đối tượng = %@", valueObject); // In ra "Object = (null)"
|
||||
|
||||
///////////////////////////////////////
|
||||
// Toán Tử (Operators)
|
||||
///////////////////////////////////////
|
||||
|
||||
// Các toán tử cũng hoạt động giống như ngôn ngữ C
|
||||
// Ví dụ:
|
||||
2 + 5; // => 7
|
||||
4.2f + 5.1f; // => 9.3f
|
||||
3 == 2; // => 0 (NO)
|
||||
3 != 2; // => 1 (YES)
|
||||
1 && 1; // => 1 (Logical and)
|
||||
0 || 1; // => 1 (Logical or)
|
||||
~0x0F; // => 0xF0 (bitwise negation)
|
||||
0x0F & 0xF0; // => 0x00 (bitwise AND)
|
||||
0x01 << 1; // => 0x02 (bitwise dịch trái (bởi 1))
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// Cấu Trúc Điều Khiển (Controls Structures)
|
||||
/////////////////////////////////////////////
|
||||
|
||||
// Câu lệnh If-Else
|
||||
if (NO)
|
||||
{
|
||||
NSLog(@"I am never run");
|
||||
} else if (0)
|
||||
{
|
||||
NSLog(@"I am also never run");
|
||||
} else
|
||||
{
|
||||
NSLog(@"I print");
|
||||
}
|
||||
|
||||
// Câu lệnh Switch
|
||||
switch (2)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
NSLog(@"I am never run");
|
||||
} break;
|
||||
case 1:
|
||||
{
|
||||
NSLog(@"I am also never run");
|
||||
} break;
|
||||
default:
|
||||
{
|
||||
NSLog(@"I print");
|
||||
} break;
|
||||
}
|
||||
|
||||
// Câu lệnh vòng lặp While
|
||||
int ii = 0;
|
||||
while (ii < 4)
|
||||
{
|
||||
NSLog(@"%d,", ii++); // ii++ tăng dần, sau khi sử dụng giá trị của nó.
|
||||
} // => in ra "0,"
|
||||
// "1,"
|
||||
// "2,"
|
||||
// "3,"
|
||||
|
||||
// Câu lệnh vòng lặp For
|
||||
int jj;
|
||||
for (jj=0; jj < 4; jj++)
|
||||
{
|
||||
NSLog(@"%d,", jj);
|
||||
} // => in ra "0,"
|
||||
// "1,"
|
||||
// "2,"
|
||||
// "3,"
|
||||
|
||||
// Câu lệnh Foreach
|
||||
NSArray *values = @[@0, @1, @2, @3];
|
||||
for (NSNumber *value in values)
|
||||
{
|
||||
NSLog(@"%@,", value);
|
||||
} // => in ra "0,"
|
||||
// "1,"
|
||||
// "2,"
|
||||
// "3,"
|
||||
|
||||
// Câu lệnh Try-Catch-Finally
|
||||
@try
|
||||
{
|
||||
// Your statements here
|
||||
@throw [NSException exceptionWithName:@"FileNotFoundException"
|
||||
reason:@"Không Tìm Thấy Tập Tin trên Hệ Thống" userInfo:nil];
|
||||
} @catch (NSException * e)
|
||||
{
|
||||
NSLog(@"Exception: %@", e);
|
||||
} @finally
|
||||
{
|
||||
NSLog(@"Finally");
|
||||
} // => in ra "Exception: Không Tìm Thấy Tập Tin trên Hệ Thống"
|
||||
// "Finally"
|
||||
|
||||
///////////////////////////////////////
|
||||
// Đối Tượng (Objects)
|
||||
///////////////////////////////////////
|
||||
|
||||
// Tạo một thực thể đối tượng bằng cách phân vùng nhớ và khởi tạo đối tượng đó.
|
||||
// Một đối tượng sẽ không thật sự hoạt động cho đến khi cả 2 bước alloc] init] được hoàn thành
|
||||
MyClass *myObject = [[MyClass alloc] init];
|
||||
|
||||
// Mô hình lập trình hướng đối tượng của Objective-C dựa trên việc truyền thông điệp (message)
|
||||
// và các thực thể đối tượng với nhau.
|
||||
// Trong Objective-C một đối tượng không đơn thuần gọi phương thức; nó truyền thông điệp.
|
||||
[myObject instanceMethodWithParameter:@"Steve Jobs"];
|
||||
|
||||
// Dọn dẹp vùng nhớ mà bạn đã dùng ở chương trình
|
||||
[pool drain];
|
||||
|
||||
// Kết thúc chương trình
|
||||
return 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////
|
||||
// Lớp và Hàm (Classes & Functions)
|
||||
///////////////////////////////////////
|
||||
|
||||
// Khai báo lớp của bạn ở một tập tin header (MyClass.h):
|
||||
// Cú pháp Khai Báo Lớp:
|
||||
// @interface ClassName : ParentClassName <ImplementedProtocols>
|
||||
// {
|
||||
// Khai báo biến thành viên;
|
||||
// }
|
||||
// -/+ (type) Khai báo method;
|
||||
// @end
|
||||
@interface MyClass : NSObject <MyProtocol>
|
||||
{
|
||||
int count;
|
||||
id data;
|
||||
NSString *name;
|
||||
}
|
||||
// Ký hiệu (notation) tiện ích để tự động khởi tạo public getter và setter
|
||||
@property int count;
|
||||
@property (copy) NSString *name; // Sao chép đối tượng trong quá trình gán.
|
||||
@property (readonly) id data; // Chỉ khai báo phương thức getter.
|
||||
|
||||
// Phương thức
|
||||
+/- (return type)methodSignature:(Parameter Type *)parameterName;
|
||||
|
||||
// dấu '+' cho phương thức lớp
|
||||
+ (NSString *)classMethod;
|
||||
|
||||
// dấu '-' cho phương thức thực thể
|
||||
- (NSString *)instanceMethodWithParameter:(NSString *)string;
|
||||
- (NSNumber *)methodAParameterAsString:(NSString*)string andAParameterAsNumber:(NSNumber *)number;
|
||||
|
||||
@end
|
||||
|
||||
// Thực thi các phương thức trong một tập tin thực thi (MyClass.m):
|
||||
|
||||
@implementation MyClass
|
||||
|
||||
// Gọi khi đối tượng được release
|
||||
- (void)dealloc
|
||||
{
|
||||
}
|
||||
|
||||
// Phương thức khởi tạo (Constructors) là một cách để tạo các lớp
|
||||
// Đây là phương thức khởi tạo mặc định được gọi khi đối tượng được khởi tạo
|
||||
- (id)init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
self.count = 1;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (NSString *)classMethod
|
||||
{
|
||||
return [[self alloc] init];
|
||||
}
|
||||
|
||||
- (NSString *)instanceMethodWithParameter:(NSString *)string
|
||||
{
|
||||
return @"New string";
|
||||
}
|
||||
|
||||
- (NSNumber *)methodAParameterAsString:(NSString*)string andAParameterAsNumber:(NSNumber *)number
|
||||
{
|
||||
return @42;
|
||||
}
|
||||
|
||||
// Các phương thức được khai báo vào MyProtocol
|
||||
- (void)myProtocolMethod
|
||||
{
|
||||
// câu lệnh
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/*
|
||||
* Một protocol khai báo các phương thức mà có thể thực thi bởi bất kỳ lớp nào.
|
||||
* Các protocol chính chúng không phải là các lớp. Chúng chỉ đơn giản là định ra giao diện (interface)
|
||||
* mà các đối tượng khác có trách nhiệm sẽ thực thi.
|
||||
*/
|
||||
@protocol MyProtocol
|
||||
- (void)myProtocolMethod;
|
||||
@end
|
||||
|
||||
|
||||
|
||||
```
|
||||
## Xem Thêm
|
||||
|
||||
+ [Wikipedia Objective-C](http://en.wikipedia.org/wiki/Objective-C)
|
||||
|
||||
+ Apple Docs':
|
||||
+ [Learning Objective-C](http://developer.apple.com/library/ios/referencelibrary/GettingStarted/Learning_Objective-C_A_Primer/)
|
||||
|
||||
+ [Programming With Objective-C](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Introduction/Introduction.html)
|
||||
|
||||
+ [Object-Oriented Programming with Objective-C](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/OOP_ObjC/Introduction/Introduction.html#//apple_ref/doc/uid/TP40005149)
|
||||
|
||||
+ [Coding Guidelines for Cocoa](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html)
|
||||
|
||||
+ [iOS For High School Students: Getting Started](http://www.raywenderlich.com/5600/ios-for-high-school-students-getting-started)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,345 +1,345 @@
|
||||
---
|
||||
language: elisp
|
||||
contributors:
|
||||
- ["Bastien Guerry", "http://bzg.fr"]
|
||||
translators:
|
||||
- ["Chenbo Li", "http://binarythink.net"]
|
||||
filename: learn-emacs-lisp-zh.el
|
||||
lang: zh-cn
|
||||
---
|
||||
|
||||
```scheme
|
||||
;; 15分钟学会Emacs Lisp (v0.2a)
|
||||
;;(作者:bzg,https://github.com/bzg
|
||||
;; 译者:lichenbo,http://douban.com/people/lichenbo)
|
||||
;;
|
||||
;; 请先阅读Peter Norvig的一篇好文:
|
||||
;; http://norvig.com/21-days.html
|
||||
;; (译者注:中文版请见http://blog.youxu.info/21-days/)
|
||||
;;
|
||||
;; 之后安装GNU Emacs 24.3:
|
||||
;;
|
||||
;; Debian: apt-get install emacs (视具体发行版而定)
|
||||
;; MacOSX: http://emacsformacosx.com/emacs-builds/Emacs-24.3-universal-10.6.8.dmg
|
||||
;; Windows: http://ftp.gnu.org/gnu/windows/emacs/emacs-24.3-bin-i386.zip
|
||||
;;
|
||||
;; 更多信息可以在这里找到:
|
||||
;; http://www.gnu.org/software/emacs/#Obtaining
|
||||
|
||||
;; 很重要的警告:
|
||||
;;
|
||||
;; 按照这个教程来学习并不会对你的电脑有任何损坏
|
||||
;; 除非你自己在学习的过程中愤怒地把它砸了
|
||||
;; 如果出现了这种情况,我不会承担任何责任
|
||||
;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;
|
||||
;; 打开emacs
|
||||
;;
|
||||
;; 按'q'消除欢迎界面
|
||||
;;
|
||||
;; 现在请注意窗口底部的那一个灰色长条
|
||||
;;
|
||||
;; "*scratch*" 是你现在编辑界面的名字。
|
||||
;; 这个编辑界面叫做一个"buffer"。
|
||||
;;
|
||||
;; 每当你打开Emacs时,都会默认打开这个scratch buffer
|
||||
;; 此时你并没有在编辑任何文件,而是在编辑一个buffer
|
||||
;; 之后你可以将这个buffer保存到一个文件中。
|
||||
;;
|
||||
;; 之后的"Lisp interaction" 则是表明我们可以用的某组命令
|
||||
;;
|
||||
;; Emacs在每个buffer中都有一组内置的命令
|
||||
;; 而当你激活某种特定的模式时,就可以使用相应的命令
|
||||
;; 这里我们使用`lisp-interaction-mode',
|
||||
;; 这样我们就可以使用内置的Emacs Lisp(以下简称Elisp)命令了。
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;
|
||||
;; 分号是注释开始的标志
|
||||
;;
|
||||
;; Elisp 是由符号表达式构成的 (即"s-表达式"或"s式"):
|
||||
(+ 2 2)
|
||||
|
||||
;; 这个s式的意思是 "对2进行加2操作".
|
||||
|
||||
;; s式周围有括号,而且也可以嵌套:
|
||||
(+ 2 (+ 1 1))
|
||||
|
||||
;; 一个s式可以包含原子符号或者其他s式
|
||||
;; 在上面的例子中,1和2是原子符号
|
||||
;; (+ 2 (+ 1 1)) 和 (+ 1 1) 是s式.
|
||||
|
||||
;; 在 `lisp-interaction-mode' 中你可以计算s式.
|
||||
;; 把光标移到闭括号后,之后按下ctrl+j(以后简写为'C-j')
|
||||
|
||||
(+ 3 (+ 1 2))
|
||||
;; ^ 光标放到这里
|
||||
;; 按下`C-j' 就会输出 6
|
||||
|
||||
;; `C-j' 会在buffer中插入当前运算的结果
|
||||
|
||||
;; 而`C-xC-e' 则会在emacs最底部显示结果,也就是被称作"minibuffer"的区域
|
||||
;; 为了避免把我们的buffer填满无用的结果,我们以后会一直用`C-xC-e'
|
||||
|
||||
;; `setq' 可以将一个值赋给一个变量
|
||||
(setq my-name "Bastien")
|
||||
;; `C-xC-e' 输出 "Bastien" (在 mini-buffer 中显示)
|
||||
|
||||
;; `insert' 会在光标处插入字符串:
|
||||
(insert "Hello!")
|
||||
;; `C-xC-e' 输出 "Hello!"
|
||||
|
||||
;; 在这里我们只传给了insert一个参数"Hello!", 但是
|
||||
;; 我们也可以传给它更多的参数,比如2个:
|
||||
|
||||
(insert "Hello" " world!")
|
||||
;; `C-xC-e' 输出 "Hello world!"
|
||||
|
||||
;; 你也可以用变量名来代替字符串
|
||||
(insert "Hello, I am " my-name)
|
||||
;; `C-xC-e' 输出 "Hello, I am Bastien"
|
||||
|
||||
;; 你可以把s式嵌入函数中
|
||||
(defun hello () (insert "Hello, I am " my-name))
|
||||
;; `C-xC-e' 输出 hello
|
||||
|
||||
;; 现在执行这个函数
|
||||
(hello)
|
||||
;; `C-xC-e' 输出 Hello, I am Bastien
|
||||
|
||||
;; 函数中空括号的意思是我们不需要接受任何参数
|
||||
;; 但是我们不能一直总是用my-name这个变量
|
||||
;; 所以我们现在使我们的函数接受一个叫做"name"的参数
|
||||
|
||||
(defun hello (name) (insert "Hello " name))
|
||||
;; `C-xC-e' 输出 hello
|
||||
|
||||
;; 现在我们调用这个函数,并且将"you"作为参数传递
|
||||
|
||||
(hello "you")
|
||||
;; `C-xC-e' 输出 "Hello you"
|
||||
|
||||
;; 成功!
|
||||
|
||||
;; 现在我们可以休息一下
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;
|
||||
;; 下面我们在新的窗口中新建一个名为 "*test*" 的buffer:
|
||||
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
;; `C-xC-e' 这时屏幕上会显示两个窗口,而光标此时位于*test* buffer内
|
||||
|
||||
;; 用鼠标单击上面的buffer就会使光标移回。
|
||||
;; 或者你可以使用 `C-xo' 使得光标跳到另一个窗口中
|
||||
|
||||
;; 你可以用 `progn'命令将s式结合起来:
|
||||
(progn
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
(hello "you"))
|
||||
;; `C-xC-e' 此时屏幕分为两个窗口,并且在*test* buffer中显示"Hello you"
|
||||
|
||||
;; 现在为了简洁,我们需要在每个s式后面都使用`C-xC-e'来执行,后面就不再说明了
|
||||
|
||||
;; 记得可以用过鼠标或者`C-xo'回到*scratch*这个buffer。
|
||||
|
||||
;; 清除当前buffer也是常用操作之一:
|
||||
(progn
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
(erase-buffer)
|
||||
(hello "there"))
|
||||
|
||||
;; 也可以回到其他的窗口中
|
||||
(progn
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
(erase-buffer)
|
||||
(hello "you")
|
||||
(other-window 1))
|
||||
|
||||
;; 你可以用 `let' 将一个值和一个局部变量绑定:
|
||||
(let ((local-name "you"))
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
(erase-buffer)
|
||||
(hello local-name)
|
||||
(other-window 1))
|
||||
|
||||
;; 这里我们就不需要使用 `progn' 了, 因为 `let' 也可以将很多s式组合起来。
|
||||
|
||||
;; 格式化字符串的方法:
|
||||
(format "Hello %s!\n" "visitor")
|
||||
|
||||
;; %s 是字符串占位符,这里被"visitor"替代.
|
||||
;; \n 是换行符。
|
||||
|
||||
;; 现在我们用格式化的方法再重写一下我们的函数:
|
||||
(defun hello (name)
|
||||
(insert (format "Hello %s!\n" name)))
|
||||
|
||||
(hello "you")
|
||||
|
||||
;; 我们再用`let'新建另一个函数:
|
||||
(defun greeting (name)
|
||||
(let ((your-name "Bastien"))
|
||||
(insert (format "Hello %s!\n\nI am %s."
|
||||
name ; the argument of the function
|
||||
your-name ; the let-bound variable "Bastien"
|
||||
))))
|
||||
|
||||
;; 之后执行:
|
||||
(greeting "you")
|
||||
|
||||
;; 有些函数可以和用户交互:
|
||||
(read-from-minibuffer "Enter your name: ")
|
||||
|
||||
;; 这个函数会返回在执行时用户输入的信息
|
||||
|
||||
;; 现在我们让`greeting'函数显示你的名字:
|
||||
(defun greeting (from-name)
|
||||
(let ((your-name (read-from-minibuffer "Enter your name: ")))
|
||||
(insert (format "Hello!\n\nI am %s and you are %s."
|
||||
from-name ; the argument of the function
|
||||
your-name ; the let-bound var, entered at prompt
|
||||
))))
|
||||
|
||||
(greeting "Bastien")
|
||||
|
||||
;; 我们让结果在另一个窗口中显示:
|
||||
(defun greeting (from-name)
|
||||
(let ((your-name (read-from-minibuffer "Enter your name: ")))
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
(erase-buffer)
|
||||
(insert (format "Hello %s!\n\nI am %s." your-name from-name))
|
||||
(other-window 1)))
|
||||
|
||||
;; 测试一下:
|
||||
(greeting "Bastien")
|
||||
|
||||
;; 第二节结束,休息一下吧。
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;
|
||||
;; 我们将一些名字存到列表中:
|
||||
(setq list-of-names '("Sarah" "Chloe" "Mathilde"))
|
||||
|
||||
;; 用 `car'来取得第一个名字:
|
||||
(car list-of-names)
|
||||
|
||||
;; 用 `cdr'取得剩下的名字:
|
||||
(cdr list-of-names)
|
||||
|
||||
;; 用 `push'把名字添加到列表的开头:
|
||||
(push "Stephanie" list-of-names)
|
||||
|
||||
;; 注意: `car' 和 `cdr' 并不修改列表本身, 但是 `push' 却会对列表本身进行操作.
|
||||
;; 这个区别是很重要的: 有些函数没有任何副作用(比如`car')
|
||||
;; 但还有一些却是有的 (比如 `push').
|
||||
|
||||
;; 我们来对`list-of-names'列表中的每一个元素都使用hello函数:
|
||||
(mapcar 'hello list-of-names)
|
||||
|
||||
;; 将 `greeting' 改进,使的我们能够对`list-of-names'中的所有名字执行:
|
||||
(defun greeting ()
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
(erase-buffer)
|
||||
(mapcar 'hello list-of-names)
|
||||
(other-window 1))
|
||||
|
||||
(greeting)
|
||||
|
||||
;; 记得我们之前定义的 `hello' 函数吗? 这个函数接受一个参数,名字。
|
||||
;; `mapcar' 调用 `hello', 并将`list-of-names'作为参数先后传给`hello'
|
||||
|
||||
;; 现在我们对显示的buffer中的内容进行一些更改:
|
||||
|
||||
(defun replace-hello-by-bonjour ()
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
(goto-char (point-min))
|
||||
(while (search-forward "Hello")
|
||||
(replace-match "Bonjour"))
|
||||
(other-window 1))
|
||||
|
||||
;; (goto-char (point-min)) 将光标移到buffer的开始
|
||||
;; (search-forward "Hello") 查找字符串"Hello"
|
||||
;; (while x y) 当x返回某个值时执行y这个s式
|
||||
;; 当x返回`nil' (空), 退出循环
|
||||
|
||||
(replace-hello-by-bonjour)
|
||||
|
||||
;; 你会看到所有在*test* buffer中出现的"Hello"字样都被换成了"Bonjour"
|
||||
|
||||
;; 你也会得到以下错误提示: "Search failed: Hello".
|
||||
;;
|
||||
;; 如果要避免这个错误, 你需要告诉 `search-forward' 这个命令是否在
|
||||
;; buffer的某个地方停止查找, 并且在什么都没找到时是否应该不给出错误提示
|
||||
|
||||
;; (search-forward "Hello" nil t) 可以达到这个要求:
|
||||
|
||||
;; `nil' 参数的意思是 : 查找并不限于某个范围内
|
||||
;; `t' 参数的意思是: 当什么都没找到时,不给出错误提示
|
||||
|
||||
;; 在下面的函数中,我们用到了s式,并且不给出任何错误提示:
|
||||
|
||||
(defun hello-to-bonjour ()
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
(erase-buffer)
|
||||
;; 为`list-of-names'中的每个名字调用hello
|
||||
(mapcar 'hello list-of-names)
|
||||
(goto-char (point-min))
|
||||
;; 将"Hello" 替换为"Bonjour"
|
||||
(while (search-forward "Hello" nil t)
|
||||
(replace-match "Bonjour"))
|
||||
(other-window 1))
|
||||
|
||||
(hello-to-bonjour)
|
||||
|
||||
;; 给这些名字加粗:
|
||||
|
||||
(defun boldify-names ()
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward "Bonjour \\(.+\\)!" nil t)
|
||||
(add-text-properties (match-beginning 1)
|
||||
(match-end 1)
|
||||
(list 'face 'bold)))
|
||||
(other-window 1))
|
||||
|
||||
;; 这个函数使用了 `re-search-forward':
|
||||
;; 和查找一个字符串不同,你用这个命令可以查找一个模式,即正则表达式
|
||||
|
||||
;; 正则表达式 "Bonjour \\(.+\\)!" 的意思是:
|
||||
;; 字符串 "Bonjour ", 之后跟着
|
||||
;; 一组 | \\( ... \\) 结构
|
||||
;; 任意字符 | . 的含义
|
||||
;; 有可能重复的 | + 的含义
|
||||
;; 之后跟着 "!" 这个字符串
|
||||
|
||||
;; 准备好了?试试看。
|
||||
|
||||
(boldify-names)
|
||||
|
||||
;; `add-text-properties' 可以添加文字属性, 比如文字样式
|
||||
|
||||
;; 好的,我们成功了!
|
||||
|
||||
;; 如果你想对一个变量或者函数有更多的了解:
|
||||
;;
|
||||
;; C-h v 变量 回车
|
||||
;; C-h f 函数 回车
|
||||
;;
|
||||
;; 阅读Emacs Lisp官方文档:
|
||||
;;
|
||||
;; C-h i m elisp 回车
|
||||
;;
|
||||
;; 在线阅读Emacs Lisp文档:
|
||||
;; https://www.gnu.org/software/emacs/manual/html_node/eintr/index.html
|
||||
|
||||
;; 感谢以下同学的建议和反馈:
|
||||
;; - Wes Hardaker
|
||||
;; - notbob
|
||||
;; - Kevin Montuori
|
||||
;; - Arne Babenhauserheide
|
||||
;; - Alan Schmitt
|
||||
;; - spacegoing
|
||||
```
|
||||
|
||||
---
|
||||
language: elisp
|
||||
contributors:
|
||||
- ["Bastien Guerry", "http://bzg.fr"]
|
||||
translators:
|
||||
- ["Chenbo Li", "http://binarythink.net"]
|
||||
filename: learn-emacs-lisp-zh.el
|
||||
lang: zh-cn
|
||||
---
|
||||
|
||||
```scheme
|
||||
;; 15分钟学会Emacs Lisp (v0.2a)
|
||||
;;(作者:bzg,https://github.com/bzg
|
||||
;; 译者:lichenbo,http://douban.com/people/lichenbo)
|
||||
;;
|
||||
;; 请先阅读Peter Norvig的一篇好文:
|
||||
;; http://norvig.com/21-days.html
|
||||
;; (译者注:中文版请见http://blog.youxu.info/21-days/)
|
||||
;;
|
||||
;; 之后安装GNU Emacs 24.3:
|
||||
;;
|
||||
;; Debian: apt-get install emacs (视具体发行版而定)
|
||||
;; MacOSX: http://emacsformacosx.com/emacs-builds/Emacs-24.3-universal-10.6.8.dmg
|
||||
;; Windows: http://ftp.gnu.org/gnu/windows/emacs/emacs-24.3-bin-i386.zip
|
||||
;;
|
||||
;; 更多信息可以在这里找到:
|
||||
;; http://www.gnu.org/software/emacs/#Obtaining
|
||||
|
||||
;; 很重要的警告:
|
||||
;;
|
||||
;; 按照这个教程来学习并不会对你的电脑有任何损坏
|
||||
;; 除非你自己在学习的过程中愤怒地把它砸了
|
||||
;; 如果出现了这种情况,我不会承担任何责任
|
||||
;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;
|
||||
;; 打开emacs
|
||||
;;
|
||||
;; 按'q'消除欢迎界面
|
||||
;;
|
||||
;; 现在请注意窗口底部的那一个灰色长条
|
||||
;;
|
||||
;; "*scratch*" 是你现在编辑界面的名字。
|
||||
;; 这个编辑界面叫做一个"buffer"。
|
||||
;;
|
||||
;; 每当你打开Emacs时,都会默认打开这个scratch buffer
|
||||
;; 此时你并没有在编辑任何文件,而是在编辑一个buffer
|
||||
;; 之后你可以将这个buffer保存到一个文件中。
|
||||
;;
|
||||
;; 之后的"Lisp interaction" 则是表明我们可以用的某组命令
|
||||
;;
|
||||
;; Emacs在每个buffer中都有一组内置的命令
|
||||
;; 而当你激活某种特定的模式时,就可以使用相应的命令
|
||||
;; 这里我们使用`lisp-interaction-mode',
|
||||
;; 这样我们就可以使用内置的Emacs Lisp(以下简称Elisp)命令了。
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;
|
||||
;; 分号是注释开始的标志
|
||||
;;
|
||||
;; Elisp 是由符号表达式构成的 (即"s-表达式"或"s式"):
|
||||
(+ 2 2)
|
||||
|
||||
;; 这个s式的意思是 "对2进行加2操作".
|
||||
|
||||
;; s式周围有括号,而且也可以嵌套:
|
||||
(+ 2 (+ 1 1))
|
||||
|
||||
;; 一个s式可以包含原子符号或者其他s式
|
||||
;; 在上面的例子中,1和2是原子符号
|
||||
;; (+ 2 (+ 1 1)) 和 (+ 1 1) 是s式.
|
||||
|
||||
;; 在 `lisp-interaction-mode' 中你可以计算s式.
|
||||
;; 把光标移到闭括号后,之后按下ctrl+j(以后简写为'C-j')
|
||||
|
||||
(+ 3 (+ 1 2))
|
||||
;; ^ 光标放到这里
|
||||
;; 按下`C-j' 就会输出 6
|
||||
|
||||
;; `C-j' 会在buffer中插入当前运算的结果
|
||||
|
||||
;; 而`C-xC-e' 则会在emacs最底部显示结果,也就是被称作"minibuffer"的区域
|
||||
;; 为了避免把我们的buffer填满无用的结果,我们以后会一直用`C-xC-e'
|
||||
|
||||
;; `setq' 可以将一个值赋给一个变量
|
||||
(setq my-name "Bastien")
|
||||
;; `C-xC-e' 输出 "Bastien" (在 mini-buffer 中显示)
|
||||
|
||||
;; `insert' 会在光标处插入字符串:
|
||||
(insert "Hello!")
|
||||
;; `C-xC-e' 输出 "Hello!"
|
||||
|
||||
;; 在这里我们只传给了insert一个参数"Hello!", 但是
|
||||
;; 我们也可以传给它更多的参数,比如2个:
|
||||
|
||||
(insert "Hello" " world!")
|
||||
;; `C-xC-e' 输出 "Hello world!"
|
||||
|
||||
;; 你也可以用变量名来代替字符串
|
||||
(insert "Hello, I am " my-name)
|
||||
;; `C-xC-e' 输出 "Hello, I am Bastien"
|
||||
|
||||
;; 你可以把s式嵌入函数中
|
||||
(defun hello () (insert "Hello, I am " my-name))
|
||||
;; `C-xC-e' 输出 hello
|
||||
|
||||
;; 现在执行这个函数
|
||||
(hello)
|
||||
;; `C-xC-e' 输出 Hello, I am Bastien
|
||||
|
||||
;; 函数中空括号的意思是我们不需要接受任何参数
|
||||
;; 但是我们不能一直总是用my-name这个变量
|
||||
;; 所以我们现在使我们的函数接受一个叫做"name"的参数
|
||||
|
||||
(defun hello (name) (insert "Hello " name))
|
||||
;; `C-xC-e' 输出 hello
|
||||
|
||||
;; 现在我们调用这个函数,并且将"you"作为参数传递
|
||||
|
||||
(hello "you")
|
||||
;; `C-xC-e' 输出 "Hello you"
|
||||
|
||||
;; 成功!
|
||||
|
||||
;; 现在我们可以休息一下
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;
|
||||
;; 下面我们在新的窗口中新建一个名为 "*test*" 的buffer:
|
||||
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
;; `C-xC-e' 这时屏幕上会显示两个窗口,而光标此时位于*test* buffer内
|
||||
|
||||
;; 用鼠标单击上面的buffer就会使光标移回。
|
||||
;; 或者你可以使用 `C-xo' 使得光标跳到另一个窗口中
|
||||
|
||||
;; 你可以用 `progn'命令将s式结合起来:
|
||||
(progn
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
(hello "you"))
|
||||
;; `C-xC-e' 此时屏幕分为两个窗口,并且在*test* buffer中显示"Hello you"
|
||||
|
||||
;; 现在为了简洁,我们需要在每个s式后面都使用`C-xC-e'来执行,后面就不再说明了
|
||||
|
||||
;; 记得可以用过鼠标或者`C-xo'回到*scratch*这个buffer。
|
||||
|
||||
;; 清除当前buffer也是常用操作之一:
|
||||
(progn
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
(erase-buffer)
|
||||
(hello "there"))
|
||||
|
||||
;; 也可以回到其他的窗口中
|
||||
(progn
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
(erase-buffer)
|
||||
(hello "you")
|
||||
(other-window 1))
|
||||
|
||||
;; 你可以用 `let' 将一个值和一个局部变量绑定:
|
||||
(let ((local-name "you"))
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
(erase-buffer)
|
||||
(hello local-name)
|
||||
(other-window 1))
|
||||
|
||||
;; 这里我们就不需要使用 `progn' 了, 因为 `let' 也可以将很多s式组合起来。
|
||||
|
||||
;; 格式化字符串的方法:
|
||||
(format "Hello %s!\n" "visitor")
|
||||
|
||||
;; %s 是字符串占位符,这里被"visitor"替代.
|
||||
;; \n 是换行符。
|
||||
|
||||
;; 现在我们用格式化的方法再重写一下我们的函数:
|
||||
(defun hello (name)
|
||||
(insert (format "Hello %s!\n" name)))
|
||||
|
||||
(hello "you")
|
||||
|
||||
;; 我们再用`let'新建另一个函数:
|
||||
(defun greeting (name)
|
||||
(let ((your-name "Bastien"))
|
||||
(insert (format "Hello %s!\n\nI am %s."
|
||||
name ; the argument of the function
|
||||
your-name ; the let-bound variable "Bastien"
|
||||
))))
|
||||
|
||||
;; 之后执行:
|
||||
(greeting "you")
|
||||
|
||||
;; 有些函数可以和用户交互:
|
||||
(read-from-minibuffer "Enter your name: ")
|
||||
|
||||
;; 这个函数会返回在执行时用户输入的信息
|
||||
|
||||
;; 现在我们让`greeting'函数显示你的名字:
|
||||
(defun greeting (from-name)
|
||||
(let ((your-name (read-from-minibuffer "Enter your name: ")))
|
||||
(insert (format "Hello!\n\nI am %s and you are %s."
|
||||
from-name ; the argument of the function
|
||||
your-name ; the let-bound var, entered at prompt
|
||||
))))
|
||||
|
||||
(greeting "Bastien")
|
||||
|
||||
;; 我们让结果在另一个窗口中显示:
|
||||
(defun greeting (from-name)
|
||||
(let ((your-name (read-from-minibuffer "Enter your name: ")))
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
(erase-buffer)
|
||||
(insert (format "Hello %s!\n\nI am %s." your-name from-name))
|
||||
(other-window 1)))
|
||||
|
||||
;; 测试一下:
|
||||
(greeting "Bastien")
|
||||
|
||||
;; 第二节结束,休息一下吧。
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;
|
||||
;; 我们将一些名字存到列表中:
|
||||
(setq list-of-names '("Sarah" "Chloe" "Mathilde"))
|
||||
|
||||
;; 用 `car'来取得第一个名字:
|
||||
(car list-of-names)
|
||||
|
||||
;; 用 `cdr'取得剩下的名字:
|
||||
(cdr list-of-names)
|
||||
|
||||
;; 用 `push'把名字添加到列表的开头:
|
||||
(push "Stephanie" list-of-names)
|
||||
|
||||
;; 注意: `car' 和 `cdr' 并不修改列表本身, 但是 `push' 却会对列表本身进行操作.
|
||||
;; 这个区别是很重要的: 有些函数没有任何副作用(比如`car')
|
||||
;; 但还有一些却是有的 (比如 `push').
|
||||
|
||||
;; 我们来对`list-of-names'列表中的每一个元素都使用hello函数:
|
||||
(mapcar 'hello list-of-names)
|
||||
|
||||
;; 将 `greeting' 改进,使的我们能够对`list-of-names'中的所有名字执行:
|
||||
(defun greeting ()
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
(erase-buffer)
|
||||
(mapcar 'hello list-of-names)
|
||||
(other-window 1))
|
||||
|
||||
(greeting)
|
||||
|
||||
;; 记得我们之前定义的 `hello' 函数吗? 这个函数接受一个参数,名字。
|
||||
;; `mapcar' 调用 `hello', 并将`list-of-names'作为参数先后传给`hello'
|
||||
|
||||
;; 现在我们对显示的buffer中的内容进行一些更改:
|
||||
|
||||
(defun replace-hello-by-bonjour ()
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
(goto-char (point-min))
|
||||
(while (search-forward "Hello")
|
||||
(replace-match "Bonjour"))
|
||||
(other-window 1))
|
||||
|
||||
;; (goto-char (point-min)) 将光标移到buffer的开始
|
||||
;; (search-forward "Hello") 查找字符串"Hello"
|
||||
;; (while x y) 当x返回某个值时执行y这个s式
|
||||
;; 当x返回`nil' (空), 退出循环
|
||||
|
||||
(replace-hello-by-bonjour)
|
||||
|
||||
;; 你会看到所有在*test* buffer中出现的"Hello"字样都被换成了"Bonjour"
|
||||
|
||||
;; 你也会得到以下错误提示: "Search failed: Hello".
|
||||
;;
|
||||
;; 如果要避免这个错误, 你需要告诉 `search-forward' 这个命令是否在
|
||||
;; buffer的某个地方停止查找, 并且在什么都没找到时是否应该不给出错误提示
|
||||
|
||||
;; (search-forward "Hello" nil t) 可以达到这个要求:
|
||||
|
||||
;; `nil' 参数的意思是 : 查找并不限于某个范围内
|
||||
;; `t' 参数的意思是: 当什么都没找到时,不给出错误提示
|
||||
|
||||
;; 在下面的函数中,我们用到了s式,并且不给出任何错误提示:
|
||||
|
||||
(defun hello-to-bonjour ()
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
(erase-buffer)
|
||||
;; 为`list-of-names'中的每个名字调用hello
|
||||
(mapcar 'hello list-of-names)
|
||||
(goto-char (point-min))
|
||||
;; 将"Hello" 替换为"Bonjour"
|
||||
(while (search-forward "Hello" nil t)
|
||||
(replace-match "Bonjour"))
|
||||
(other-window 1))
|
||||
|
||||
(hello-to-bonjour)
|
||||
|
||||
;; 给这些名字加粗:
|
||||
|
||||
(defun boldify-names ()
|
||||
(switch-to-buffer-other-window "*test*")
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward "Bonjour \\(.+\\)!" nil t)
|
||||
(add-text-properties (match-beginning 1)
|
||||
(match-end 1)
|
||||
(list 'face 'bold)))
|
||||
(other-window 1))
|
||||
|
||||
;; 这个函数使用了 `re-search-forward':
|
||||
;; 和查找一个字符串不同,你用这个命令可以查找一个模式,即正则表达式
|
||||
|
||||
;; 正则表达式 "Bonjour \\(.+\\)!" 的意思是:
|
||||
;; 字符串 "Bonjour ", 之后跟着
|
||||
;; 一组 | \\( ... \\) 结构
|
||||
;; 任意字符 | . 的含义
|
||||
;; 有可能重复的 | + 的含义
|
||||
;; 之后跟着 "!" 这个字符串
|
||||
|
||||
;; 准备好了?试试看。
|
||||
|
||||
(boldify-names)
|
||||
|
||||
;; `add-text-properties' 可以添加文字属性, 比如文字样式
|
||||
|
||||
;; 好的,我们成功了!
|
||||
|
||||
;; 如果你想对一个变量或者函数有更多的了解:
|
||||
;;
|
||||
;; C-h v 变量 回车
|
||||
;; C-h f 函数 回车
|
||||
;;
|
||||
;; 阅读Emacs Lisp官方文档:
|
||||
;;
|
||||
;; C-h i m elisp 回车
|
||||
;;
|
||||
;; 在线阅读Emacs Lisp文档:
|
||||
;; https://www.gnu.org/software/emacs/manual/html_node/eintr/index.html
|
||||
|
||||
;; 感谢以下同学的建议和反馈:
|
||||
;; - Wes Hardaker
|
||||
;; - notbob
|
||||
;; - Kevin Montuori
|
||||
;; - Arne Babenhauserheide
|
||||
;; - Alan Schmitt
|
||||
;; - spacegoing
|
||||
```
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user