mirror of
https://github.com/alrayyes/wiki.git
synced 2024-11-24 20:46:22 +00:00
Quartz sync: Oct 30, 2024, 6:27 PM
This commit is contained in:
parent
5139864e15
commit
1ff8ec2771
633 changed files with 23051 additions and 0 deletions
161
content/wiki/20200613170532-variable_types_in_javascript.md
Normal file
161
content/wiki/20200613170532-variable_types_in_javascript.md
Normal file
|
@ -0,0 +1,161 @@
|
|||
---
|
||||
date: 2020-06-13
|
||||
id: 8af0e4ee-b090-4903-9ab7-020a4b7328ef
|
||||
title: JavaScript Variables
|
||||
---
|
||||
|
||||
# Types
|
||||
|
||||
## Numbers
|
||||
|
||||
JavaScript uses 64 bits to store number values
|
||||
|
||||
### Fractional numbers
|
||||
|
||||
``` javascript
|
||||
console.log(9.81)
|
||||
```
|
||||
|
||||
### Scientific notation
|
||||
|
||||
``` javascript
|
||||
console.log(2.998e8)
|
||||
```
|
||||
|
||||
### Special Numbers
|
||||
|
||||
1. Infinity
|
||||
|
||||
Infinity and -Infinity represent positive and negative infinities
|
||||
|
||||
``` javascript
|
||||
console.log(Infinity - 1)
|
||||
console.log(Infinity + 1)
|
||||
console.log(-Infinity - 1)
|
||||
console.log(-Infinity + 1)
|
||||
```
|
||||
|
||||
2. NaN
|
||||
|
||||
Not a number. The returned result if you try to do mathematical
|
||||
nonsense
|
||||
|
||||
``` javascript
|
||||
console.log(0/0)
|
||||
console.log(Infinity - Infinity)
|
||||
```
|
||||
|
||||
## Strings
|
||||
|
||||
Following are acceptable strings
|
||||
|
||||
``` javascript
|
||||
console.log(`Down on the sea`)
|
||||
console.log("Lie on the ocean")
|
||||
console.log('Float on the ocean')
|
||||
```
|
||||
|
||||
Backslash escapes characters
|
||||
|
||||
``` javascript
|
||||
console.log("This is the first line\nAnd this is the second")
|
||||
console.log("A newline character is written like \"\\n\".")
|
||||
```
|
||||
|
||||
Backtick quoted strings ([template
|
||||
literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals))
|
||||
can span lines and also embed other values. \${} in a template literal
|
||||
will be computed and converted to a string
|
||||
|
||||
``` javascript
|
||||
console.log(`This is a
|
||||
backtick quotes string`)
|
||||
console.log(`half of 100 is ${100 / 2}`)
|
||||
```
|
||||
|
||||
## Boolean
|
||||
|
||||
``` javascript
|
||||
console.log(3 > 2)
|
||||
console.log(3 < 2)
|
||||
```
|
||||
|
||||
Strings can also be compared
|
||||
|
||||
``` javascript
|
||||
console.log("Aardvark" < "Zoroaster")
|
||||
```
|
||||
|
||||
Uppercase characters are always less than lower case characters, so "Z"
|
||||
\< "a". Non alphabetic characters are less than alphabetic characters
|
||||
|
||||
``` javascript
|
||||
console.log("Zebra" < "aardvark")
|
||||
console.log("!" < "aardvark")
|
||||
console.log("!" < "Zebra")
|
||||
console.log("3" < "Zebra")
|
||||
console.log("!" < "3")
|
||||
```
|
||||
|
||||
## Empty values
|
||||
|
||||
There are two special empty values, null & undefined that denote the
|
||||
absence of any meaningful value. They can be used interchangeably and
|
||||
are an [accident of JavaScripts
|
||||
design](https://medium.com/@stephenthecurt/a-brief-history-of-null-and-undefined-in-javascript-c283caab662e).
|
||||
|
||||
``` javascript
|
||||
console.log(null == undefined);
|
||||
```
|
||||
|
||||
# ES6
|
||||
|
||||
## Symbols
|
||||
|
||||
They are tokens that serve as unique IDs. You create symbols via the
|
||||
factory function Symbol() (which is loosely similar to String returning
|
||||
strings if called as a function):
|
||||
|
||||
``` javascript
|
||||
const symbol1 = Symbol();
|
||||
```
|
||||
|
||||
### Add a description
|
||||
|
||||
``` javascript
|
||||
const tralala = Symbol('tralala')
|
||||
console.log(tralala) // Symbol(tralala)
|
||||
```
|
||||
|
||||
### Convert to string
|
||||
|
||||
``` javascript
|
||||
const tralala = Symbol('tralala')
|
||||
console.log(String(tralala)) // `Symbol(tralala)`
|
||||
```
|
||||
|
||||
### Every Symbol is unique
|
||||
|
||||
``` javascript
|
||||
console.log(Symbol() === Symbol()) // false
|
||||
```
|
||||
|
||||
### Property keys
|
||||
|
||||
``` javascript
|
||||
const KEY = Symbol();
|
||||
const obj = {};
|
||||
|
||||
obj[KEY] = 123;
|
||||
console.log(obj[KEY]); // 123
|
||||
```
|
||||
|
||||
``` javascript
|
||||
const FOO = Symbol();
|
||||
const obj = {
|
||||
[FOO]() {
|
||||
return 'bar';
|
||||
}
|
||||
};
|
||||
console.log(obj[FOO]()); // bar
|
||||
```
|
27
content/wiki/20200613170705-operators_in_javascript.md
Normal file
27
content/wiki/20200613170705-operators_in_javascript.md
Normal file
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
date: 2020-06-13
|
||||
id: a8f1290e-b4ef-4f80-bc21-69ddb4c22aca
|
||||
title: JavaScript Operators
|
||||
---
|
||||
|
||||
# Operators
|
||||
|
||||
- [Arithmetic
|
||||
Operators](20201112103849-javascript_arithmetic_operators)
|
||||
- [Comparison
|
||||
Operators](20201112105310-javascript_comparison_operators)
|
||||
- [Conditional (Ternary)
|
||||
Operator](20201112110025-javascript_conditional_ternary_operator)
|
||||
- [Nullish coalescing operator
|
||||
(??)](20201116162237-nullish_coalescing_operator)
|
||||
- [Optional Chaining Operator
|
||||
(?.)](20201116162628-optional_chaining_operator)
|
||||
- [Object Operators](20201113090050-javascript_object_operators)
|
||||
- [String Operators](20201112104819-javascript_string_operators)
|
||||
- [Unary Operators](20201112105050-javascript_unary_operators)
|
||||
|
||||
# Logical operators
|
||||
|
||||
- [Logical Operators](20201112105647-javascript_logical_operators)
|
||||
- [Short Circuiting of Logical
|
||||
Operators](20201112105833-javascript_short_circuiting_of_logical_operators)
|
17
content/wiki/20200613170756-javascript_type_conversion.md
Normal file
17
content/wiki/20200613170756-javascript_type_conversion.md
Normal file
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
date: 2020-06-13
|
||||
id: 9e542d77-7a1f-4f6b-a48d-ce12afc68101
|
||||
title: JavaScript Type Conversion
|
||||
---
|
||||
|
||||
# Syntax
|
||||
|
||||
``` javascript
|
||||
console.log(8 * null)
|
||||
console.log("5" - 1)
|
||||
console.log("5" + 1)
|
||||
console.log("five" * 2)
|
||||
console.log(false == 0)
|
||||
console.log(false == "")
|
||||
console.log(null == 0)
|
||||
```
|
17
content/wiki/20200613170756-type_conversion_in_javascript.md
Normal file
17
content/wiki/20200613170756-type_conversion_in_javascript.md
Normal file
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
date: 2020-06-13
|
||||
id: cc70a2c4-2d57-4a17-8c52-ba5f143d830c
|
||||
title: Type conversion in JavaScript
|
||||
---
|
||||
|
||||
# Type conversion
|
||||
|
||||
``` javascript
|
||||
console.log(8 * null)
|
||||
console.log("5" - 1)
|
||||
console.log("5" + 1)
|
||||
console.log("five" * 2)
|
||||
console.log(false == 0)
|
||||
console.log(false == "")
|
||||
console.log(null == 0)
|
||||
```
|
135
content/wiki/20200613170905-javascript.md
Normal file
135
content/wiki/20200613170905-javascript.md
Normal file
|
@ -0,0 +1,135 @@
|
|||
---
|
||||
date: 2020-06-13
|
||||
id: 6adaacc0-8c1e-4fb3-99c2-50db5bcbfa6b
|
||||
title: JavaScript
|
||||
---
|
||||
|
||||
# Language
|
||||
|
||||
## Objects
|
||||
|
||||
- [Arrays](20200826201029-arrays)
|
||||
- [Objects](20200826201605-objects)
|
||||
|
||||
## Types
|
||||
|
||||
- [Numbers](20200922164416-numbers)
|
||||
- [Strings](20200922164551-strings)
|
||||
- [Booleans](20200922164727-booleans)
|
||||
- [Empty values](20200922164830-empty_values)
|
||||
- [Numbers](20200922164416-numbers)
|
||||
- [BigInt](20201116165819-javascript_bigint)
|
||||
|
||||
## Values Operators
|
||||
|
||||
- [Operators](20200613170705-operators_in_javascript)
|
||||
- [Type Conversion](20200613170756-javascript_type_conversion)
|
||||
- [Destructuring](20200922160850-destructuring)
|
||||
- [Spread (…)](20201014094144-spread)
|
||||
|
||||
## Program Structure
|
||||
|
||||
- [Binding /
|
||||
Variables](20200613172137-binding_variables_in_javascript)
|
||||
- [Control flows](20200613172534-javascript_control_flows)
|
||||
|
||||
## Functions
|
||||
|
||||
- [Bindings and scopes](20200702203250-bindings_and_scopes)
|
||||
- [Closure](20200702204351-closure)
|
||||
- [Recursion](20200702204437-recursion)
|
||||
- [Higher-order functions](20200827142818-higher_order_functions)
|
||||
- [Generators](20200911155947-generators)
|
||||
|
||||
### Definitions
|
||||
|
||||
- [Function
|
||||
Declarations](20201006111125-javascript_function_declerations)
|
||||
- [Declaration notation](20201006111244-declaration_notation)
|
||||
- [Arrow Functions](20201006111349-arrow_functions)
|
||||
|
||||
### Parameters
|
||||
|
||||
- [Optional arguments](20200702204226-optional_arguments)
|
||||
- [Parameter default values](20200922162003-parameter_default_values)
|
||||
- [Named parameters](20200922162127-named_parameters)
|
||||
- [Rest parameters](20200922162500-rest_parameters)
|
||||
|
||||
## Classes
|
||||
|
||||
- [Class Notation](20201008090316-class_notation)
|
||||
- [Method Definition](20201008090449-method_definition)
|
||||
- [Inheritance](20201008090613-inheritance)
|
||||
- [Getters &
|
||||
setters](20201007093418-javascript_object_getters_setters)
|
||||
|
||||
## Structures
|
||||
|
||||
- [Maps](20201012093745-javascript_maps)
|
||||
- [WeakMaps](20201012094749-javascript_weakmaps)
|
||||
- [Sets](20201012094248-javascript_sets)
|
||||
|
||||
## Standard Libraries
|
||||
|
||||
- [Error handling](20200901105237-error_handling)
|
||||
- [Regular expressions](20200902162305-regular_expressions)
|
||||
- [Number](20200923153425-number)
|
||||
- [Math](20200923153614-math)
|
||||
|
||||
## Modules
|
||||
|
||||
- [CommonJS](20200916172802-commonjs)
|
||||
- [ECMAScript](20200916172914-ecmascript)
|
||||
|
||||
## Asynchronous Programming
|
||||
|
||||
- [Callbacks](20200911150451-callbacks)
|
||||
- [Promises](20200911154351-promises)
|
||||
- [Async functions](20201026103714-javascript_async_functions)
|
||||
|
||||
## Iterables & Iterators
|
||||
|
||||
- [Iterables](20201014092625-javascript_iterables)
|
||||
- [Iterator](20201014092846-javascript_iterator)
|
||||
- [Async Iterator](20201030092200-javascript_async_iterator)
|
||||
|
||||
## Metaprogramming
|
||||
|
||||
- [Proxies](20201022094207-javascript_proxies)
|
||||
- [Metaprogramming](20201022095438-javascript_metaprogramming)
|
||||
|
||||
## Comments
|
||||
|
||||
- [Comments](20201030094749-javascript_comments)
|
||||
|
||||
## Rest / Spread Properties
|
||||
|
||||
- [Rest Operator (…) in Object
|
||||
Destructuring](20201103111357-rest_operator_in_object_destructuring)
|
||||
|
||||
## Imports
|
||||
|
||||
- [Dynamic Import](20201116170151-dynamic_import)
|
||||
- [Module Namespace Exports](20201116170347-module_namespace_exports)
|
||||
|
||||
## Misc
|
||||
|
||||
- [globalThis](20201116170538-globalthis)
|
||||
|
||||
# Frameworks
|
||||
|
||||
- [Vue.js](20201021141613-vue_js)
|
||||
- [React](20201130084544-react)
|
||||
|
||||
# Changelog
|
||||
|
||||
- [ES6](20201030093404-es6)
|
||||
- [ES2016](20201023130243-es2016)
|
||||
- [ES2017](20201026104538-es2017)
|
||||
- [ES2018](20201030095105-es2018)
|
||||
- [ES2019](20201113111815-es2019)
|
||||
- [ES2020](20201116162058-es2020)
|
||||
|
||||
# Sources
|
||||
|
||||
- [Books](20200613170934-javascript_books)
|
14
content/wiki/20200613170934-javascript_books.md
Normal file
14
content/wiki/20200613170934-javascript_books.md
Normal file
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
date: 2020-06-13
|
||||
id: 116e53fb-3830-473d-9474-57c8b45aa996
|
||||
title: JavaScript Books
|
||||
---
|
||||
|
||||
# Some handy JavaScript books
|
||||
|
||||
- [Eloquent JavaScript](https://eloquentjavascript.net/)
|
||||
- [Exploring ES6](https://exploringjs.com/es6.html)
|
||||
- [Exploring ES2016 and
|
||||
ES2017](https://exploringjs.com/es2016-es2017.html)
|
||||
- [Exploring ES2018 and
|
||||
ES2019](https://exploringjs.com/es2018-es2019/index.html)
|
84
content/wiki/20200613171743-javascript_types.md
Normal file
84
content/wiki/20200613171743-javascript_types.md
Normal file
|
@ -0,0 +1,84 @@
|
|||
---
|
||||
date: 2020-06-13
|
||||
id: cb93f6ba-527b-4602-b5f4-de0281897800
|
||||
title: JavaScript Types
|
||||
---
|
||||
|
||||
# Numbers
|
||||
|
||||
JavaScript uses 64 bits to store number values
|
||||
|
||||
## Fractional numbers
|
||||
|
||||
``` javascript
|
||||
console.log(9.81)
|
||||
```
|
||||
|
||||
## Scientific notation
|
||||
|
||||
``` javascript
|
||||
console.log(2.998e8)
|
||||
```
|
||||
|
||||
## Special Numbers
|
||||
|
||||
### Infinity
|
||||
|
||||
Infinity and -Infinity represent positive and negative infinities
|
||||
|
||||
``` javascript
|
||||
console.log(Infinity - 1)
|
||||
console.log(Infinity + 1)
|
||||
console.log(-Infinity - 1)
|
||||
console.log(-Infinity + 1)
|
||||
```
|
||||
|
||||
### NaN
|
||||
|
||||
Not a number. The returned result if you try to do mathematical nonsense
|
||||
|
||||
``` javascript
|
||||
console.log(0/0)
|
||||
console.log(Infinity - Infinity)
|
||||
```
|
||||
|
||||
# Boolean
|
||||
|
||||
``` javascript
|
||||
console.log(3 > 2)
|
||||
console.log(3 < 2)
|
||||
```
|
||||
|
||||
Strings can also be compared
|
||||
|
||||
``` javascript
|
||||
console.log("Aardvark" < "Zoroaster")
|
||||
```
|
||||
|
||||
Uppercase characters are always less than lower case characters, so "Z"
|
||||
\< "a". Non alphabetic characters are less than alphabetic characters
|
||||
|
||||
``` javascript
|
||||
console.log("Zebra" < "aardvark")
|
||||
console.log("!" < "aardvark")
|
||||
console.log("!" < "Zebra")
|
||||
console.log("3" < "Zebra")
|
||||
console.log("!" < "3")
|
||||
```
|
||||
|
||||
# Empty values
|
||||
|
||||
There are two special empty values, null & undefined that denote the
|
||||
absence of any meaningful value. They can be used interchangeably and
|
||||
are an [accident of JavaScripts
|
||||
design](https://medium.com/@stephenthecurt/a-brief-history-of-null-and-undefined-in-javascript-c283caab662e).
|
||||
|
||||
``` javascript
|
||||
console.log(null == undefined);
|
||||
```
|
||||
|
||||
# Related
|
||||
|
||||
- [JavaScript](20200613170905-javascript)
|
||||
- [Arrays](20200826201029-arrays)
|
||||
- [Strings](20200922164551-strings)
|
|
@ -0,0 +1,46 @@
|
|||
---
|
||||
date: 2020-06-13
|
||||
id: 6efc70be-8154-420f-a92e-622ef1ad960c
|
||||
title: Binding / Variables in JavaScript
|
||||
---
|
||||
|
||||
# ES6
|
||||
|
||||
## Let
|
||||
|
||||
``` javascript
|
||||
let caught = 5 * 5
|
||||
console.log(caught)
|
||||
|
||||
let mood = "light"
|
||||
console.log(mood)
|
||||
mood = "dark"
|
||||
console.log(mood)
|
||||
|
||||
let luigisDebt = 140;
|
||||
luigisDebt = luigisDebt - 35;
|
||||
console.log(luigisDebt);
|
||||
```
|
||||
|
||||
A single let statement my define multiple bindings
|
||||
|
||||
``` javascript
|
||||
let one = 1, two = 2
|
||||
console.log(one + two)
|
||||
```
|
||||
|
||||
## Const
|
||||
|
||||
This is a constant binding. It points to the same value for as long as
|
||||
it lives
|
||||
|
||||
``` javascript
|
||||
const blaat = "abcd"
|
||||
console.log(blaat)
|
||||
/**
|
||||
* Following will both cause errors:
|
||||
*
|
||||
* blaat = "efgh"
|
||||
* let blaat = "efgh"
|
||||
*/
|
||||
```
|
132
content/wiki/20200613172534-control_flows_in_javascript.md
Normal file
132
content/wiki/20200613172534-control_flows_in_javascript.md
Normal file
|
@ -0,0 +1,132 @@
|
|||
---
|
||||
date: 2020-06-13
|
||||
id: adffc782-d978-49f3-9367-33e77b05af8a
|
||||
title: Control flows in JavaScript
|
||||
---
|
||||
|
||||
# ES6
|
||||
|
||||
## for-of
|
||||
|
||||
``` javascript
|
||||
const arr = ['a', 'b', 'c'];
|
||||
for (const elem of arr) {
|
||||
console.log(elem);
|
||||
}
|
||||
```
|
||||
|
||||
``` javascript
|
||||
const arr = ['a', 'b', 'c'];
|
||||
for (const [index, elem] of arr.entries()) {
|
||||
console.log(index+'. '+elem);
|
||||
}
|
||||
```
|
||||
|
||||
# if statement
|
||||
|
||||
``` javascript
|
||||
if(true === true) {
|
||||
console.log("True is true")
|
||||
}
|
||||
|
||||
if (true === false) {
|
||||
console.log("True is false")
|
||||
}
|
||||
else {
|
||||
console.log("True is not false")
|
||||
}
|
||||
```
|
||||
|
||||
# while statement
|
||||
|
||||
``` javascript
|
||||
let i = 0
|
||||
while (i <= 5) {
|
||||
console.log("Loop " + i)
|
||||
i++
|
||||
}
|
||||
|
||||
let j = 0
|
||||
do {
|
||||
j++
|
||||
} while (j <= 5)
|
||||
console.log("Do while j value is " + j)
|
||||
```
|
||||
|
||||
# for statement
|
||||
|
||||
``` javascript
|
||||
for(let k = 0; k <= 5; k++) {
|
||||
console.log("For loop k " + k)
|
||||
}
|
||||
```
|
||||
|
||||
# switch statement
|
||||
|
||||
``` javascript
|
||||
switch ("rainy") {
|
||||
case "rainy":
|
||||
console.log("Remember to bring an umbrella.");
|
||||
break;
|
||||
case "sunny":
|
||||
console.log("Dress lightly.");
|
||||
case "cloudy":
|
||||
console.log("Go outside.");
|
||||
break;
|
||||
default:
|
||||
console.log("Unknown weather type!");
|
||||
break;
|
||||
}
|
||||
|
||||
switch ("sunny") {
|
||||
case "rainy":
|
||||
console.log("Remember to bring an umbrella.");
|
||||
break;
|
||||
case "sunny":
|
||||
console.log("Dress lightly.");
|
||||
case "cloudy":
|
||||
console.log("Go outside.");
|
||||
break;
|
||||
default:
|
||||
console.log("Unknown weather type!");
|
||||
break;
|
||||
}
|
||||
|
||||
switch ("wild card") {
|
||||
case "rainy":
|
||||
console.log("Remember to bring an umbrella.");
|
||||
break;
|
||||
case "sunny":
|
||||
console.log("Dress lightly.");
|
||||
case "cloudy":
|
||||
console.log("Go outside.");
|
||||
break;
|
||||
default:
|
||||
console.log("Unknown weather type!");
|
||||
break;
|
||||
}
|
||||
```
|
||||
|
||||
# Breaking out of a loop
|
||||
|
||||
``` javascript
|
||||
for (let current = 20; ; current = current + 1) {
|
||||
if (current % 7 == 0) {
|
||||
console.log(current);
|
||||
break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# Comments
|
||||
|
||||
``` javascript
|
||||
// This is a one line comment
|
||||
let i = 0
|
||||
|
||||
/**
|
||||
This is a multi line comment
|
||||
Here is the second line
|
||||
*/
|
||||
let j = 0
|
||||
```
|
26
content/wiki/20200613172534-javascript_control_flows.md
Normal file
26
content/wiki/20200613172534-javascript_control_flows.md
Normal file
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
date: 2020-06-13
|
||||
id: 65258dfb-bf3f-454a-8219-a22a29cb1683
|
||||
title: JavaScript Control Flows
|
||||
---
|
||||
|
||||
# Statements
|
||||
|
||||
- [if statement](20201030093832-javascript_if_statement)
|
||||
- [while statement](20201030093956-javascript_while_statement)
|
||||
- [for statement](20201030094040-javascript_for_statement)
|
||||
- [for await of](20201030095741-javascript_for_await_of)
|
||||
- [for of statement](20201030093304-javascript_for_of)
|
||||
- [switch statement](20201030094138-javascript_switch_statement)
|
||||
- [try catch](20201116154444-javascript_catch_binding)
|
||||
|
||||
# Catch binding
|
||||
|
||||
- [Catch Binding](20201116154444-javascript_catch_binding)
|
||||
- [Optional Catch
|
||||
Binding](20201116154824-javascript_optional_catch_binding)
|
||||
|
||||
# Misc
|
||||
|
||||
- [Breaking out of a
|
||||
loop](20201030094343-javascript_breaking_out_of_a_loop)
|
65
content/wiki/20200702203250-bindings_and_scopes.md
Normal file
65
content/wiki/20200702203250-bindings_and_scopes.md
Normal file
|
@ -0,0 +1,65 @@
|
|||
---
|
||||
date: 2020-07-02
|
||||
id: 40bc3b60-ab05-4ff6-a258-f5cb38322c77
|
||||
title: Bindings and scopes in JavaScript
|
||||
---
|
||||
|
||||
# Bindings
|
||||
|
||||
- For bindings defined outside of any function or block, the scope is
|
||||
the whole program. We call these `global` bindings
|
||||
- Bindings created for function parameters or declared inside a
|
||||
function can only be referenced in that function. These are known as
|
||||
`local` bindings. New instances of these `local` bindings are
|
||||
created every time the function is called
|
||||
- Bindings declared with `let` and `const` are local to the block that
|
||||
they are declared in
|
||||
- In pre-2015 JavaScript, only functions created new scopes. So
|
||||
old-style bindings created with `var` are visible throughout the
|
||||
whole function that they appear in. If not declared in a function
|
||||
then scope is `global`
|
||||
|
||||
``` javascript
|
||||
let x = 10
|
||||
if (true) {
|
||||
let y = 20
|
||||
var z = 30
|
||||
console.log(x + y + z)
|
||||
}
|
||||
|
||||
// y is not accessable here
|
||||
console.log(x + z)
|
||||
```
|
||||
|
||||
``` javascript
|
||||
const halve = function(n) {
|
||||
return n / 2
|
||||
}
|
||||
|
||||
let n = 10
|
||||
|
||||
console.log(halve(100))
|
||||
console.log(n)
|
||||
```
|
||||
|
||||
# Nested scope
|
||||
|
||||
``` javascript
|
||||
const hummus = function(factor) {
|
||||
const ingredient = function(amount, unit, name) {
|
||||
let ingredientAmount = amount * factor;
|
||||
if (ingredientAmount > 1) {
|
||||
unit += "s";
|
||||
}
|
||||
console.log(`${ingredientAmount} ${unit} ${name}`);
|
||||
};
|
||||
ingredient(1, "can", "chickpeas");
|
||||
ingredient(0.25, "cup", "tahini");
|
||||
ingredient(0.25, "cup", "lemon juice");
|
||||
ingredient(1, "clove", "garlic");
|
||||
ingredient(2, "tablespoon", "olive oil");
|
||||
ingredient(0.5, "teaspoon", "cumin");
|
||||
};
|
||||
|
||||
hummus(1)
|
||||
```
|
40
content/wiki/20200702204226-optional_arguments.md
Normal file
40
content/wiki/20200702204226-optional_arguments.md
Normal file
|
@ -0,0 +1,40 @@
|
|||
---
|
||||
date: 2020-07-02
|
||||
id: 6e1019ae-983e-42c6-90cf-daa6aebb86ea
|
||||
title: Optional arguments in JavaScript functions
|
||||
---
|
||||
|
||||
JavaScript is extremely broad-minded about the number of arguments you
|
||||
pass to a function. If you pass too many, the extra ones are ignored. If
|
||||
you pass too few, the missing parameters get assigned the value
|
||||
`undefined`.
|
||||
|
||||
``` javascript
|
||||
function square(x) { return x * x; }
|
||||
console.log(square(4, true, "hedgehog"));
|
||||
```
|
||||
|
||||
``` javascript
|
||||
function minus(a, b) {
|
||||
if (b === undefined) return -a;
|
||||
else return a - b;
|
||||
}
|
||||
|
||||
console.log(minus(10));
|
||||
console.log(minus(10, 5));
|
||||
```
|
||||
|
||||
Function parameters can also be given default values
|
||||
|
||||
``` javascript
|
||||
function power(base, exponent = 2) {
|
||||
let result = 1;
|
||||
for (let count = 0; count < exponent; count++) {
|
||||
result *= base;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
console.log(power(4));
|
||||
console.log(power(2, 6));
|
||||
```
|
35
content/wiki/20200702204351-closure.md
Normal file
35
content/wiki/20200702204351-closure.md
Normal file
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
date: 2020-07-02
|
||||
id: 8659a753-2c0d-46cb-afdc-095e318aabff
|
||||
title: Closure in JavaScript
|
||||
---
|
||||
|
||||
Local bindings are created anew for every call, and different calls
|
||||
can't affect on another calls local bindings.
|
||||
|
||||
``` javascript
|
||||
function wrapValue(n) {
|
||||
let local = n;
|
||||
return () => local;
|
||||
}
|
||||
|
||||
let wrap1 = wrapValue(1);
|
||||
let wrap2 = wrapValue(2);
|
||||
console.log(wrap1());
|
||||
console.log(wrap2());
|
||||
```
|
||||
|
||||
A function that references bindings from local scopes around it is
|
||||
called a closure. This behavior not only frees you from having to worry
|
||||
about lifetimes of bindings but also makes it possible to use function
|
||||
values in some creative ways.
|
||||
|
||||
``` javascript
|
||||
function multiplier(factor) {
|
||||
return number => number * factor;
|
||||
}
|
||||
|
||||
let twice = multiplier(2);
|
||||
|
||||
console.log(twice(5));
|
||||
```
|
17
content/wiki/20200702204437-recursion.md
Normal file
17
content/wiki/20200702204437-recursion.md
Normal file
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
date: 2020-07-02
|
||||
id: f77e6e36-1674-46b6-a8c9-d5a77d40f19e
|
||||
title: Recursion in JavaScript
|
||||
---
|
||||
|
||||
``` javascript
|
||||
function power(base, exponent) {
|
||||
if (exponent == 0) {
|
||||
return 1;
|
||||
} else {
|
||||
return base * power(base, exponent - 1);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(power(2, 3));
|
||||
```
|
25
content/wiki/20200704151304-history.md
Normal file
25
content/wiki/20200704151304-history.md
Normal file
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
date: 2020-07-04
|
||||
id: ed692a43-3267-4b5d-a0a7-cef4a25b4fda
|
||||
title: History
|
||||
---
|
||||
|
||||
# USSR
|
||||
|
||||
- [Economic state of USSR
|
||||
1942-1943](20200704151508-economic_state_of_ussr_1942_1943)
|
||||
|
||||
# Islamic History
|
||||
|
||||
- [Stages of Islamic
|
||||
History](20200706161134-stages_of_islamic_history)
|
||||
- [The Chaldeans](20200706165803-the_chaldeans)
|
||||
|
||||
# Western History
|
||||
|
||||
- [Stages of Christian
|
||||
history](20200706164411-stages_of_christian_history)
|
||||
|
||||
# Misc
|
||||
|
||||
- [Historical Terms](20201029195742-historical_terms)
|
|
@ -0,0 +1,77 @@
|
|||
---
|
||||
date: 2020-07-04
|
||||
id: de009f15-07b5-4e76-8976-349c949bc148
|
||||
title: Economic state of USSR 1942-1943
|
||||
---
|
||||
|
||||
# Outline
|
||||
|
||||
- Impossible to calculate as Soviet figures are unreliable at best.
|
||||
Relying on convergence of anecdotal evidence
|
||||
- Source - Economics of ww2 by Harrison
|
||||
- Cats & dogs going missing in Moscow
|
||||
- People going to the front because food is so bad at home
|
||||
- 62nd/63rd/64th army running out of food
|
||||
- Roosevelt tells Molatov in 42 that he'll send less food to start the
|
||||
second front in 43 instead of 44. Molatov doesn't want this, he
|
||||
prefers food
|
||||
- Census is done in 37. Stalin didn't like the results and had the
|
||||
people who did the census shot. Next census showed the correct
|
||||
numbers
|
||||
- In controlled communist economies prices of goods are made up by
|
||||
government and are therefore meaningless
|
||||
- Soviet Union were in dire economic straits. If Stalingrad was won by
|
||||
the Germans they would probably have collapsed
|
||||
|
||||
# Pre war economy
|
||||
|
||||
## Agriculture
|
||||
|
||||
| Country | Working population in agriculture | Output of non agricultural worker |
|
||||
|----|----|----|
|
||||
| USSR | 57% | 33% |
|
||||
| Germany | 26% | 50% |
|
||||
| USA | 17% | 40% |
|
||||
| UK | 6% | 59% |
|
||||
|
||||
- Agricultural workers in USSR were female because men were drafted
|
||||
for the war or in gulags
|
||||
- Amount of rubels spent on the economy dropped from 58.3bn in 1940 to
|
||||
31.6bn in 1942
|
||||
- Inflation was also rampant which amplified the problems
|
||||
- Ukraine & caucuses were taken by Germany. the wheat basket
|
||||
- Collectivised farms were terrible for productivity
|
||||
- Soviet citizens average daily intake of calories from 1942-1943 is
|
||||
estimated to have been 2555 calories. In 1944 this was increased to
|
||||
2810 calories. 500 calories less than average german/british
|
||||
civilian. Americans ate 1000 more.
|
||||
- Dispossed/hungry licked plates of others meals
|
||||
- Communist leadership ate well
|
||||
- 200-300 grams of sub standard bread
|
||||
- Soviets ate half as much food as US citizens on average
|
||||
- Zhukov boasted his men lived on 1000 calories / day during the
|
||||
battle of Stalingrad
|
||||
- between 1940-1942 real output of civilian branches feel from 1/2 to
|
||||
2/3
|
||||
- By 1942 agricultural output fell to 44% of pre war (1937) level
|
||||
according to official Soviet numbers
|
||||
- 50m people in USSR employed in agriculture in 1940. By 1942 figure
|
||||
dropped to 25m according to official USSR numbers
|
||||
- Half the population were covered by official rationing system
|
||||
- 80% of the rations were bread
|
||||
- After 1942 mortality rates in Siberia decreased because the weakest
|
||||
already died off
|
||||
|
||||
# Gulags
|
||||
|
||||
- In gulags rations were decreased dramatically. from 1942-1943 people
|
||||
were starving in gulags
|
||||
- During war years 5m people were in gulag system. 1m were released to
|
||||
the front. Majority left in gulags were ill and infirm. They were
|
||||
given light work. Even before the war food wasn't provided in enough
|
||||
quantities in 1939
|
||||
- camp mortality reached it peak in 1942 when 50k prisoners died every
|
||||
month.
|
||||
- Over 2m people died in gulags and camps during war years
|
||||
- Household consumption by workers decreased by 2 fifths from
|
||||
1940-1942
|
8
content/wiki/20200704151715-economics.md
Normal file
8
content/wiki/20200704151715-economics.md
Normal file
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
date: 2020-07-04
|
||||
id: 2e431131-c786-4718-964c-b0ff972de8da
|
||||
title: Economics
|
||||
---
|
||||
|
||||
- [Economic state of USSR
|
||||
1942-1943](20200704151508-economic_state_of_ussr_1942_1943)
|
120
content/wiki/20200704151950-ledger.md
Normal file
120
content/wiki/20200704151950-ledger.md
Normal file
|
@ -0,0 +1,120 @@
|
|||
---
|
||||
date: 2020-07-04
|
||||
id: 38f9bc4b-06de-4f23-9626-3e4dad348dd3
|
||||
title: Ledger
|
||||
---
|
||||
|
||||
# Common [Ledger](https://www.ledger-cli.org/) CLI Commands ([Source](https://gist.githubusercontent.com/agarrharr/03450c1be7f6b3d2b883c6b5e317d2aa/raw/4c5bfa57be1cd98a232e3f4bda0fcc2a51ba0862/index.md))
|
||||
|
||||
## Income vs expenses this month?
|
||||
|
||||
``` bash
|
||||
ledger balance income expenses --period "this month"
|
||||
```
|
||||
|
||||
## What did my budget look like at a certain date?
|
||||
|
||||
``` bash
|
||||
ledger balance budget --end 2018-01-02
|
||||
```
|
||||
|
||||
This is how it looked at the end of the day on Jan 1, 2018.
|
||||
|
||||
## How much is in the checking account right now?
|
||||
|
||||
``` bash
|
||||
ledger balance checking
|
||||
```
|
||||
|
||||
## What is our net worth?
|
||||
|
||||
``` bash
|
||||
ledger balance ^assets ^liabilities --real
|
||||
```
|
||||
|
||||
## How much money have we made?
|
||||
|
||||
``` bash
|
||||
ledger balance income
|
||||
```
|
||||
|
||||
## How much money have we made from our salaries?
|
||||
|
||||
``` bash
|
||||
ledger balance income:salary
|
||||
```
|
||||
|
||||
## How much do we spend each month on x?
|
||||
|
||||
``` bash
|
||||
ledger register -M expenses:groceries:food
|
||||
```
|
||||
|
||||
## Group transactions by payee
|
||||
|
||||
``` bash
|
||||
ledger register --by-payee
|
||||
```
|
||||
|
||||
## Only show uncleared transactions
|
||||
|
||||
``` bash
|
||||
ledger register --uncleared
|
||||
```
|
||||
|
||||
## Do I have enough budgeted to pay off my credit cards?
|
||||
|
||||
``` bash
|
||||
ledger balance creditcard
|
||||
```
|
||||
|
||||
It should be \$0.00. If it's not \$0.00, run this with different dates
|
||||
to find the problem:
|
||||
|
||||
``` bash
|
||||
ledger balance creditcard --end 2018-02-01
|
||||
```
|
||||
|
||||
## Import
|
||||
|
||||
Change Chase checking from:
|
||||
|
||||
``` example
|
||||
Details,Posting Date,Description,Amount,Type,Balance,Check or Slip #
|
||||
```
|
||||
|
||||
to:
|
||||
|
||||
``` example
|
||||
,Date,Payee,Amount,,,Code
|
||||
```
|
||||
|
||||
Change Chase Credit Card from:
|
||||
|
||||
``` example
|
||||
Type,Trans Date,Post Date,Description,Amount
|
||||
```
|
||||
|
||||
to:
|
||||
|
||||
``` example
|
||||
,Date,Posted,Payee,Amount
|
||||
```
|
||||
|
||||
``` bash
|
||||
ledger convert ~/Downloads/checking.CSV --input-date-format "%m/%d/%Y" --invert --account Assets:Checking --rich-data -f budget.ledger --auto-match --pager less
|
||||
```
|
||||
|
||||
## Expenses each month (sorted)
|
||||
|
||||
``` bash
|
||||
ledger -M --period-sort "(amount)" reg ^expenses
|
||||
```
|
||||
|
||||
This will show all expenses, grouped by month and sorted by the amount.
|
||||
|
||||
## How much do we spend on credit cards each month?
|
||||
|
||||
``` bash
|
||||
ledger -M -r --display 'account=~/creditcard/' reg ^expenses
|
||||
```
|
62
content/wiki/20200704152249-vocabulary.md
Normal file
62
content/wiki/20200704152249-vocabulary.md
Normal file
|
@ -0,0 +1,62 @@
|
|||
---
|
||||
date: 2020-07-04
|
||||
id: 726cec04-6f79-42e8-8677-63d8980f5ca4
|
||||
title: Vocabulary
|
||||
---
|
||||
|
||||
# Categories
|
||||
|
||||
- [Architecture](20201109123541-architecture)
|
||||
- [Chess Terms](20201109120843-chess_terms)
|
||||
- [Clothing](20201109123123-clothing)
|
||||
- [Furniture](20201104090504-furniture)
|
||||
- [Geographic Terms](20201029195945-geographic_terms)
|
||||
- [Glassware](20201109123853-glassware)
|
||||
- [Historical Terms](20201029195742-historical_terms)
|
||||
- [Political science terms](20201029200040-political_science_terms)
|
||||
- [Programming Terms](20201126095254-programming_terms)
|
||||
- [Sexual terms](20201029200327-sexual_terms)
|
||||
- [Tongue Twisters](20201109122104-tongue_twisters)
|
||||
|
||||
# Adjectives, nouns & verbs
|
||||
|
||||
- [Adjectives](20201029204304-adjectives)
|
||||
- [Nouns](20201030183237-nouns)
|
||||
- [Verbs](20201030182939-verbs)
|
||||
|
||||
# Complete list
|
||||
|
||||
- [anathema](20201109122445-anathema)
|
||||
- [antecedent](20201030195742-antecedent)
|
||||
- [antimacassar](20201109122731-antimacassar)
|
||||
- [anteroom](20201109123452-anteroom)
|
||||
- [bluestocking](20201029201415-bluestocking)
|
||||
- [Carthaginian peace](20201029194838-carthaginian_peace)
|
||||
- [chenille](20201109121858-chenille)
|
||||
- [chiffonier](20201104090229-chiffonier)
|
||||
- [decanter](20201109123736-decanter)
|
||||
- [detritus](20201029195142-detritus)
|
||||
- [eidetic](20201109124059-eidetic)
|
||||
- [epaulet](20201109121407-epaulet)
|
||||
- [fianchetto](20201109120912-fianchetto)
|
||||
- [gaberdine](20201109123003-gaberdine)
|
||||
- [geld](20201030183019-geld)
|
||||
- [gregarious](20201029204128-gregarious)
|
||||
- [imperturbable](20201109121645-imperturbable)
|
||||
- [inchmeal](20201109124204-inchmeal)
|
||||
- [indolent](20201116182958-indolent)
|
||||
- [Intercommunicating zones](20201029195404-intercommunicating_zones)
|
||||
- [insouciance](20201109121245-insouciance)
|
||||
- [mirth](20201109121522-mirth)
|
||||
- [percolate](20201109121108-percolate)
|
||||
- [perfunctory](20201109122833-perfunctory)
|
||||
- [podophilia](20201029200235-podophilia)
|
||||
- [précis](20201109122314-precis)
|
||||
- [prig](20201109122557-prig)
|
||||
- [rancor](20201109123923-rancor)
|
||||
- [sanguine](20201109123624-sanguine)
|
||||
- [tawdry](20220917160601-tawdry)
|
||||
- [Useful idiot](20201029195302-useful_idiot)
|
||||
- [viscosity](20210405123214-viscosity)
|
||||
- [wily](20201109121740-wily)
|
||||
- [worsted](20201109123326-worsted)
|
66
content/wiki/20200704152442-rust.md
Normal file
66
content/wiki/20200704152442-rust.md
Normal file
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
date: 2020-07-04
|
||||
id: 882564c6-4258-40f4-87ec-fb5b267b7ac2
|
||||
title: Rust
|
||||
---
|
||||
|
||||
- [Rust Tooling](20201119165530-rust_tooling)
|
||||
|
||||
# API
|
||||
|
||||
- [Functions](20201120110719-rust_functions)
|
||||
- [Primitive Types](20201120095639-rust_primitive_types)
|
||||
- [Structs](20201120105306-rust_structs)
|
||||
- [Traits](20201120103547-rust_traits)
|
||||
|
||||
# Language
|
||||
|
||||
- [Comments](20200827190035-rust_comments)
|
||||
- [Control flow](20200827190443-rust_control_flow)
|
||||
- [Enums](20200902150714-enums)
|
||||
- [Iterators](20200923150006-iterators)
|
||||
- [Ownership](20200828170945-ownership)
|
||||
- [Pointers](20201120102004-rust_pointers)
|
||||
- [Structs](20200831193417-structs)
|
||||
- [Tests](20200918183524-tests)
|
||||
- [Variables](20200827171554-variables_in_rust)
|
||||
|
||||
## Common Collections
|
||||
|
||||
- [Vectors](20200915140449-vectors)
|
||||
- [Strings](20200915151358-strings)
|
||||
- [Hash Maps](20200915153033-hash_maps)
|
||||
|
||||
## Concurrency
|
||||
|
||||
- [Threads](20200930121904-rust_threads)
|
||||
- [Message passing](20200930123003-message_passing)
|
||||
- [Shared-State
|
||||
Concurrency](20200930123749-rust_shared_state_concurrency)
|
||||
|
||||
## Error handling
|
||||
|
||||
- [Unrecoverable Errors](20200916162727-unrecoverable_errors)
|
||||
- [Recoverable Errors](20200916163737-recoverable_errors)
|
||||
|
||||
## Functions
|
||||
|
||||
- [Functions & macros](20200827170931-functions_macros)
|
||||
- [Closures](20200923144022-closures)
|
||||
|
||||
## Generic Types and Traits
|
||||
|
||||
- [Generics](20200917161757-generics)
|
||||
- [Traits](20200917163203-traits)
|
||||
|
||||
## Patterns and Matching
|
||||
|
||||
- [Pattern Syntax](20201006102934-pattern_syntax)
|
||||
|
||||
# Misc
|
||||
|
||||
- [Books & exercises](20200827171318-rust_books)
|
||||
|
||||
# Changelog
|
||||
|
||||
- [1.48](20201119165257-rust_1_48)
|
20
content/wiki/20200706161134-stages_of_islamic_history.md
Normal file
20
content/wiki/20200706161134-stages_of_islamic_history.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
date: 2020-07-06
|
||||
id: 61037644-f96f-4ab2-8ea5-4f8829b4de9c
|
||||
title: The 10 stages of Islamic History
|
||||
---
|
||||
|
||||
Islamic history can roughly be divided into 10 stages (as opposed to
|
||||
[the 10 stages of Christian
|
||||
history](20200706164411-stages_of_christian_history)):
|
||||
|
||||
1. Ancient Times: Mesopotamia and Persia
|
||||
2. Birth of Islam
|
||||
3. The Caliphate: Quest for Universal Unity
|
||||
4. Fragmentation: Age of the Sultanates
|
||||
5. Catastrophe: Crusaders and Mongols
|
||||
6. Rebirth: The Three-Empires Era
|
||||
7. Permeation of East by West
|
||||
8. The Reform Movements
|
||||
9. Triumph of the Secular Modernists
|
||||
10. The Islamist Reaction
|
22
content/wiki/20200706164411-stages_of_christian_history.md
Normal file
22
content/wiki/20200706164411-stages_of_christian_history.md
Normal file
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
date: 2020-07-06
|
||||
id: baac5bf7-b54a-4fed-927b-e8a4f220e81c
|
||||
title: The 10 stages of Christian history
|
||||
---
|
||||
|
||||
When the ideal future envisioned by post industrialized, Western
|
||||
democratic society is taken as the endpoint of history, the shape of the
|
||||
narrative leading to here-and-now features something like the following
|
||||
stages (as opposed to [the 10 stages of Islamic
|
||||
history](20200706161134-stages_of_islamic_history)):
|
||||
|
||||
1. Birth of civilization (Egypt and Mesopotamia)
|
||||
2. Classical age (Greece and Rome)
|
||||
3. The Dark Ages (rise of Christianity)
|
||||
4. The Rebirth: Renaissance and Reformation
|
||||
5. The Enlightenment (exploration and science)
|
||||
6. The Revolutions (democratic, industrial, technological)
|
||||
7. Rise of Nation-States: The Struggle for Empire
|
||||
8. World Wars I and II.
|
||||
9. The Cold War
|
||||
10. The Triumph of Democratic Capitalism
|
15
content/wiki/20200706165803-the_chaldeans.md
Normal file
15
content/wiki/20200706165803-the_chaldeans.md
Normal file
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
date: 2020-07-06
|
||||
id: fcbdb286-af0e-484f-8a2d-dd5b2e18ff5b
|
||||
title: The Chaldeans
|
||||
---
|
||||
|
||||
The Assyrians fell at last to one of their subject peoples, the
|
||||
Chaldeans, who rebuilt Babylon and won a lustrous place in history for
|
||||
their intellectual achievements in astronomy, medicine, and mathematics.
|
||||
They used a base-12 system (as opposed to our base-10 system) and were
|
||||
pioneers in the measurement and division of time, which is why the year
|
||||
has twelve months, the hour has sixty minutes (five times twelve), and
|
||||
the minute has sixty seconds. They were terrific urban planners and
|
||||
architects—it was a Chaldean king who built those Hanging Gardens of
|
||||
Babylon, which the ancients ranked among the seven wonders of the world.
|
59
content/wiki/20200826142641-golang.md
Normal file
59
content/wiki/20200826142641-golang.md
Normal file
|
@ -0,0 +1,59 @@
|
|||
---
|
||||
date: 2020-08-26
|
||||
id: 3e8fc539-e90c-4278-a233-6158dbca89e4
|
||||
title: Golang
|
||||
---
|
||||
|
||||
# Language
|
||||
|
||||
## Basics
|
||||
|
||||
- [Packages](20200826142755-packages)
|
||||
- [Functions](20200826151337-functions)
|
||||
- [Variables](20200826151514-variables)
|
||||
- [Flow control statements](20200826151846-flow_control_statements)
|
||||
- [Tests](20200826191127-tests)
|
||||
- [Tooling](20200826191508-tooling)
|
||||
- [Pointers](20200828180957-pointers)
|
||||
- [Structs](20200828181259-structs)
|
||||
- [Arrays](20200828182327-arrays)
|
||||
- [Slices](20200828182546-slices)
|
||||
- [Maps](20200828192034-maps)
|
||||
- [Methods](20200831155304-methods)
|
||||
- [Interfaces](20200831171822-interfaces)
|
||||
- [Errors](20200909202454-errors)
|
||||
- [Reflection](20200917155644-reflection)
|
||||
- [Context](20200921154246-context)
|
||||
- [Embedding](20200928193245-embedding)
|
||||
|
||||
## Concurrency
|
||||
|
||||
- [Goroutines](20200901141141-goroutines)
|
||||
|
||||
### Sync
|
||||
|
||||
- [Mutex](20200918173820-mutex)
|
||||
- [WaitGroup](20200918174548-waitgroup)
|
||||
|
||||
### Misc
|
||||
|
||||
- When to use sync.Mutex or a channel[^1]
|
||||
|
||||
## Libraries you should probably know about
|
||||
|
||||
- http[^2]
|
||||
|
||||
## Books & tutorials
|
||||
|
||||
- Go by Example[^3]
|
||||
- Learn Go with tests[^4]
|
||||
|
||||
# Footnotes
|
||||
|
||||
[^1]: <https://faiface.github.io/post/context-should-go-away-go2/>
|
||||
|
||||
[^2]: <https://golang.org/pkg/net/http/>
|
||||
|
||||
[^3]: <https://gobyexample.com/>
|
||||
|
||||
[^4]: <https://quii.gitbook.io/learn-go-with-tests/>
|
66
content/wiki/20200826142755-packages.md
Normal file
66
content/wiki/20200826142755-packages.md
Normal file
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
date: 2020-08-26
|
||||
id: 3123184d-c919-4cf6-8339-3f9b8ca5a1db
|
||||
title: Golang Packages
|
||||
---
|
||||
|
||||
# Basics
|
||||
|
||||
Every Go program is made up of packages. Programs start running in
|
||||
package \`main\`.
|
||||
|
||||
By convention the pacckage name is the same as the last element of the
|
||||
import path. For instance, the \`math/rand\` package comprises files
|
||||
that begin with the statement \`package rand\`.
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("My favorite number is", rand.Intn(10))
|
||||
}
|
||||
```
|
||||
|
||||
# Imports
|
||||
|
||||
It's best practice to convert multiple import statements to a "factored"
|
||||
import statement:
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
import "math"
|
||||
|
||||
func main() {
|
||||
fmt.Printf("This uses multiple import statements\n")
|
||||
fmt.Printf("Now you have %g problems.\n", math.Sqrt(7))
|
||||
}
|
||||
```
|
||||
|
||||
should be
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Printf("This uses a parenthesized \"factored\" import statement\n")
|
||||
fmt.Printf("Now you have %g problems.\n", math.Sqrt(7))
|
||||
}
|
||||
```
|
||||
|
||||
# Exported names
|
||||
|
||||
In Go, a name is exported if it begins with a capital letter. When
|
||||
importing a package, you can refer only to its exported names. Any
|
||||
"unexported" names are not accessible from outside the package.
|
195
content/wiki/20200826151337-functions.md
Normal file
195
content/wiki/20200826151337-functions.md
Normal file
|
@ -0,0 +1,195 @@
|
|||
---
|
||||
date: 2020-08-26
|
||||
id: 009236f9-033d-44ef-8fa4-73cb05c3b390
|
||||
title: Golang Functions
|
||||
---
|
||||
|
||||
# Arguments
|
||||
|
||||
## Basics
|
||||
|
||||
A function can take zero or more arguments. [Argument type comes after
|
||||
the variable name](https://blog.golang.org/declaration-syntax).
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func add(x int, y int) int {
|
||||
return x + y
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println(add(42, 13))
|
||||
}
|
||||
```
|
||||
|
||||
When two or more consecutive named function parameters share a type, you
|
||||
can omit the type from all but the last
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func add(x, y int) int {
|
||||
return x + y
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println(add(42, 13))
|
||||
}
|
||||
```
|
||||
|
||||
## Variadic
|
||||
|
||||
Go also supports [variadic
|
||||
functions](https://gobyexample.com/variadic-functions), ie functions
|
||||
with any number of trailing arguments:
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func sum(nums ...int) {
|
||||
fmt.Print(nums, " ")
|
||||
total := 0
|
||||
for _, num := range nums {
|
||||
total += num
|
||||
}
|
||||
fmt.Println(total)
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
sum(1, 2)
|
||||
sum(1, 2, 3)
|
||||
|
||||
nums := []int{1, 2, 3, 4}
|
||||
sum(nums...)
|
||||
}
|
||||
```
|
||||
|
||||
# Returns
|
||||
|
||||
## Multiple results
|
||||
|
||||
A function can return any number of results
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func swap(x, y string) (string, string) {
|
||||
return y, x
|
||||
}
|
||||
|
||||
func main() {
|
||||
a, b := swap("hello", "world")
|
||||
fmt.Println(a, b)
|
||||
}
|
||||
```
|
||||
|
||||
## Named return values
|
||||
|
||||
Go's return values may be named. If so, they are treated as variables
|
||||
defined at the top of the function. These names shoudl be used to
|
||||
document the meaning of the return values. A \`return\` statement
|
||||
without arguments returns the named return values. This is known as a
|
||||
"naked" return. Naked return statements should be used only short
|
||||
functions as they can harm readability in longer functions.
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func split(sum int) (x, y int) {
|
||||
x = sum * 4 / 9
|
||||
y = sum - x
|
||||
return
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println(split(17))
|
||||
}
|
||||
```
|
||||
|
||||
## Function values
|
||||
|
||||
Like in [JavaScript](20200613170905-javascript) functions can be passed
|
||||
around
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
func compute(fn func(float64, float64) float64) float64 {
|
||||
return fn(3, 4)
|
||||
}
|
||||
|
||||
func main() {
|
||||
hypot := func(x, y float64) float64 {
|
||||
return math.Sqrt(x*x + y*y)
|
||||
}
|
||||
fmt.Println(hypot(5, 12))
|
||||
|
||||
fmt.Println(compute(hypot))
|
||||
fmt.Println(compute(math.Pow))
|
||||
}
|
||||
```
|
||||
|
||||
## Function closures
|
||||
|
||||
Like [JavaScript](20200613170905-javascript) function closures are
|
||||
supported in Go as well
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func adder() func(int) int {
|
||||
sum := 0
|
||||
return func(x int) int {
|
||||
sum += x
|
||||
return sum
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
pos, neg := adder(), adder()
|
||||
for i := 0; i < 10; i++ {
|
||||
fmt.Println(
|
||||
pos(i),
|
||||
neg(-2*i),
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# Implementing an Interface
|
||||
|
||||
Here is an example of a function implementing an
|
||||
[interface](20200831171822-interfaces):
|
||||
|
||||
``` go
|
||||
type BlindAlerter interface {
|
||||
ScheduleAlertAt(duration time.Duration, amount int)
|
||||
}
|
||||
|
||||
// BlindAlerterFunc allows you to implement BlindAlerter with a function
|
||||
type BlindAlerterFunc func(duration time.Duration, amount int)
|
||||
|
||||
// ScheduleAlertAt is BlindAlerterFunc implementation of BlindAlerter
|
||||
func (a BlindAlerterFunc) ScheduleAlertAt(duration time.Duration, amount int) {
|
||||
a(duration, amount)
|
||||
}
|
||||
```
|
232
content/wiki/20200826151514-variables.md
Normal file
232
content/wiki/20200826151514-variables.md
Normal file
|
@ -0,0 +1,232 @@
|
|||
---
|
||||
date: 2020-08-26
|
||||
id: ef9ed7f2-0bee-4405-a6d2-993cdea80029
|
||||
title: Golang variables
|
||||
---
|
||||
|
||||
# Basics
|
||||
|
||||
The \`var\` statement declares a list of variables. Type is last. A
|
||||
\`var\` statement can be at package or function level. Use var when you
|
||||
to set a variable type but don't want to set the variable value yet.
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
var c, python, java bool
|
||||
|
||||
func main() {
|
||||
var i int
|
||||
fmt.Println(i, c, python, java)
|
||||
}
|
||||
```
|
||||
|
||||
This also works with [interfaces](20200831171822-interfaces).
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type printSomething interface {
|
||||
print()
|
||||
}
|
||||
|
||||
type agent struct {
|
||||
}
|
||||
|
||||
func (d *agent) print() {
|
||||
fmt.Println("tralala")
|
||||
}
|
||||
|
||||
var (
|
||||
a = &agent{}
|
||||
)
|
||||
|
||||
func main() {
|
||||
a.print()
|
||||
}
|
||||
```
|
||||
|
||||
# Initializers
|
||||
|
||||
A var declaration can include initializers, one per variable. If an
|
||||
initializer is present, the type can be omitted; the variable will take
|
||||
the type of the initializer.
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
var i, j int = 1, 2
|
||||
|
||||
func main() {
|
||||
var c, python, java = true, false, "no!"
|
||||
fmt.Println(i, j, c, python, java)
|
||||
}
|
||||
```
|
||||
|
||||
# Short variable declarations
|
||||
|
||||
Inside a function, the := short assignment statement can be used in
|
||||
place of a var declaration with implicit type. Outside a function, every
|
||||
statement begins with a keyword (var, func, and so on) and so the :=
|
||||
construct is not available.
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
var i, j int = 1, 2
|
||||
k := 3
|
||||
c, python, java := true, false, "no!"
|
||||
|
||||
fmt.Println(i, j, k, c, python, java)
|
||||
}
|
||||
```
|
||||
|
||||
# Basic types
|
||||
|
||||
Go's basic types are
|
||||
|
||||
bool
|
||||
|
||||
string
|
||||
|
||||
int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptr
|
||||
|
||||
byte // alias for uint8
|
||||
|
||||
rune // alias for int32 // represents a Unicode code point
|
||||
|
||||
float32 float64
|
||||
|
||||
complex64 complex128
|
||||
|
||||
The example shows variables of several types, and also that variable
|
||||
declarations may be "factored" into blocks, as with import statements.
|
||||
|
||||
The int, uint, and uintptr types are usually 32 bits wide on 32-bit
|
||||
systems and 64 bits wide on 64-bit systems. When you need an integer
|
||||
value you should use int unless you have a specific reason to use a
|
||||
sized or unsigned integer type.
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/cmplx"
|
||||
)
|
||||
|
||||
var (
|
||||
ToBe bool = false
|
||||
MaxInt uint64 = 1<<64 - 1
|
||||
z complex128 = cmplx.Sqrt(-5 + 12i)
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Printf("Type: %T Value: %v\n", ToBe, ToBe)
|
||||
fmt.Printf("Type: %T Value: %v\n", MaxInt, MaxInt)
|
||||
fmt.Printf("Type: %T Value: %v\n", z, z)
|
||||
}
|
||||
```
|
||||
|
||||
# Zero values
|
||||
|
||||
Variables declared without an explicit initial value are given their
|
||||
zero value.
|
||||
|
||||
The zero value is:
|
||||
|
||||
- 0 for numeric types
|
||||
- false for the boolean type
|
||||
- "" for strings
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
var i int
|
||||
var f float64
|
||||
var b bool
|
||||
var s string
|
||||
fmt.Printf("%v %v %v %q\n", i, f, b, s)
|
||||
}
|
||||
```
|
||||
|
||||
# Type conversions
|
||||
|
||||
The expression \`T(v)\` converts the value v to the type T.
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var x, y int = 3, 4
|
||||
var f float64 = math.Sqrt(float64(x*x + y*y))
|
||||
var z uint = uint(f)
|
||||
fmt.Println(x, y, z)
|
||||
}
|
||||
```
|
||||
|
||||
# Type inference
|
||||
|
||||
When declaring a variable without specifying an explicit type (either by
|
||||
using the := syntax or var = expression syntax), the variable's type is
|
||||
inferred from the value on the right hand side.
|
||||
|
||||
When the right hand side of the declaration is typed, the new variable
|
||||
is of that same type:
|
||||
|
||||
``` go
|
||||
var i int
|
||||
j := i // j is an int
|
||||
```
|
||||
|
||||
But when the right hand side contains an untyped numeric constant, the
|
||||
new variable may be an int, float64, or complex128 depending on the
|
||||
precision of the constant:
|
||||
|
||||
``` go
|
||||
i := 42 // int
|
||||
f := 3.142 // float64
|
||||
g := 0.867 + 0.5i // complex128
|
||||
```
|
||||
|
||||
# Constants
|
||||
|
||||
Constants are declared like variables, but with the const keyword.
|
||||
|
||||
Constants can be character, string, boolean, or numeric values.
|
||||
|
||||
Constants cannot be declared using the := syntax.
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
const Pi = 3.14
|
||||
|
||||
func main() {
|
||||
const World = "世界"
|
||||
fmt.Println("Hello", World)
|
||||
fmt.Println("Happy", Pi, "Day")
|
||||
|
||||
const Truth = true
|
||||
fmt.Println("Go rules?", Truth)
|
||||
}
|
||||
```
|
268
content/wiki/20200826151846-flow_control_statements.md
Normal file
268
content/wiki/20200826151846-flow_control_statements.md
Normal file
|
@ -0,0 +1,268 @@
|
|||
---
|
||||
date: 2020-08-26
|
||||
id: db553cc1-625c-4ddf-8d3c-cc0bba7b4345
|
||||
title: Golang flow control statements
|
||||
---
|
||||
|
||||
# For
|
||||
|
||||
Go has no \`while\`, \`do\` or \`until\` keywords for iteration, only
|
||||
\`for\`
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
sum := 0
|
||||
for i := 0; i < 10; i++ {
|
||||
sum += i
|
||||
}
|
||||
fmt.Println(sum)
|
||||
}
|
||||
```
|
||||
|
||||
Init and post statements are optional:
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
sum := 1
|
||||
for ; sum < 1000; {
|
||||
sum += sum
|
||||
}
|
||||
fmt.Println(sum)
|
||||
}
|
||||
```
|
||||
|
||||
For is Go's "while":
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
sum := 1
|
||||
for sum < 1000 {
|
||||
sum += sum
|
||||
}
|
||||
fmt.Println(sum)
|
||||
}
|
||||
```
|
||||
|
||||
Infinite loops are possible as well:
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
func main() {
|
||||
for {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Iterate over [Golang Arrays](20200828182327-arrays) & [Golang
|
||||
slices](20200828182546-slices) with \`range\`:
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var numbers = []int{1,2,3,4,5}
|
||||
var sum = 0
|
||||
|
||||
for _, number := range numbers {
|
||||
sum += number
|
||||
}
|
||||
|
||||
fmt.Println("%s", sum)
|
||||
}
|
||||
```
|
||||
|
||||
# If
|
||||
|
||||
Like for, the if statement can start with a short statement to execute
|
||||
before the condition.
|
||||
|
||||
Variables declared by the statement are only in scope until the end of
|
||||
the if.
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
func pow(x, n, lim float64) float64 {
|
||||
if v := math.Pow(x, n); v < lim {
|
||||
return v
|
||||
}
|
||||
return lim
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println(
|
||||
pow(3, 2, 10),
|
||||
pow(3, 3, 20),
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Variables declared inside an if short statement are also available
|
||||
inside any of the else blocks.
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
func pow(x, n, lim float64) float64 {
|
||||
if v := math.Pow(x, n); v < lim {
|
||||
return v
|
||||
} else {
|
||||
fmt.Printf("%g >= %g\n", v, lim)
|
||||
}
|
||||
// can't use v here, though
|
||||
return lim
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println(
|
||||
pow(3, 2, 10),
|
||||
pow(3, 3, 20),
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
# Switch
|
||||
|
||||
Go's switch is like the one in C, C++, Java, JavaScript, and PHP, except
|
||||
that Go only runs the selected case, not all the cases that follow. In
|
||||
effect, the break statement that is needed at the end of each case in
|
||||
those languages is provided automatically in Go. Another important
|
||||
difference is that Go's switch cases need not be constants, and the
|
||||
values involved need not be integers.
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Print("Go runs on ")
|
||||
switch os := runtime.GOOS; os {
|
||||
case "darwin":
|
||||
fmt.Println("OS X.")
|
||||
case "linux":
|
||||
fmt.Println("Linux.")
|
||||
default:
|
||||
// freebsd, openbsd,
|
||||
// plan9, windows...
|
||||
fmt.Printf("%s.\n", os)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Switch without a condition is the same as switch true. This construct
|
||||
can be a clean way to write long if-then-else chains.
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
t := time.Now()
|
||||
switch {
|
||||
case t.Hour() < 12:
|
||||
fmt.Println("Good morning!")
|
||||
case t.Hour() < 17:
|
||||
fmt.Println("Good afternoon.")
|
||||
default:
|
||||
fmt.Println("Good evening.")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Type switches are also a thing:
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func do(i interface{}) {
|
||||
switch v := i.(type) {
|
||||
case int:
|
||||
fmt.Printf("Twice %v is %v\n", v, v*2)
|
||||
case string:
|
||||
fmt.Printf("%q is %v bytes long\n", v, len(v))
|
||||
default:
|
||||
fmt.Printf("I don't know about type %T!\n", v)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
do(21)
|
||||
do("hello")
|
||||
do(true)
|
||||
}
|
||||
```
|
||||
|
||||
# Defer
|
||||
|
||||
A defer statement defers the execution of a function until the
|
||||
surrounding function returns. The deferred call's arguments are
|
||||
evaluated immediately, but the function call is not executed until the
|
||||
surrounding function returns.
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
defer fmt.Println("world")
|
||||
|
||||
fmt.Println("hello")
|
||||
}
|
||||
```
|
||||
|
||||
Deferred function calls are pushed onto a stack. When a function
|
||||
returns, its deferred calls are executed in last-in-first-out order.
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Println("counting")
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
defer fmt.Println(i)
|
||||
}
|
||||
|
||||
fmt.Println("done")
|
||||
}
|
||||
```
|
205
content/wiki/20200826191127-tests.md
Normal file
205
content/wiki/20200826191127-tests.md
Normal file
|
@ -0,0 +1,205 @@
|
|||
---
|
||||
date: 2020-08-26
|
||||
id: d8edb970-fe2c-4774-b325-2f932b262ef5
|
||||
title: Tests in Golang
|
||||
---
|
||||
|
||||
# Rules
|
||||
|
||||
Test writing rules:
|
||||
|
||||
- It needs to be in a file with a name like \`xxx~test~.go\`
|
||||
- The test funciton must start with the word \`Test\`
|
||||
- The test function takes one argument only \`t \*testing.T\`
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestHello(t *testing.T) {
|
||||
assertCorrectMessage := func(t *testing.T, got, want string) {
|
||||
t.Helper()
|
||||
if got != want {
|
||||
t.Errorf("got %q want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("saying hello to people", func(t *testing.T) {
|
||||
got := Hello("Chris", "")
|
||||
want := "Hello, Chris"
|
||||
assertCorrectMessage(t, got, want)
|
||||
})
|
||||
|
||||
t.Run("empty string defaults to 'World'", func(t *testing.T) {
|
||||
got := Hello("", "")
|
||||
want := "Hello, World"
|
||||
assertCorrectMessage(t, got, want)
|
||||
})
|
||||
|
||||
t.Run("in Spanish", func(t *testing.T) {
|
||||
got := Hello("Elodie", "Spanish")
|
||||
want := "Hola, Elodie"
|
||||
assertCorrectMessage(t, got, want)
|
||||
})
|
||||
|
||||
t.Run("in French", func(t *testing.T) {
|
||||
got := Hello("Jean Pierre", "French")
|
||||
want := "Bonjour, Jean Pierre"
|
||||
assertCorrectMessage(t, got, want)
|
||||
})
|
||||
|
||||
t.Run("in Dutch", func(t *testing.T) {
|
||||
got := Hello("Frans", "Dutch")
|
||||
want := "Hoi, Frans"
|
||||
assertCorrectMessage(t, got, want)
|
||||
})
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
# Examples
|
||||
|
||||
Examples can also be added to ~test~.go files.
|
||||
|
||||
``` go
|
||||
func ExampleAdd() {
|
||||
sum := Add(1, 5)
|
||||
fmt.Println(sum)
|
||||
// Output: 6
|
||||
}
|
||||
```
|
||||
|
||||
Example function will not be execute if the comment is removed
|
||||
|
||||
# Benchmarking
|
||||
|
||||
[Benchmarks](https://golang.org/pkg/testing/#hdr-Benchmarks) are a
|
||||
first-class feature of Go, fantastic stuff!
|
||||
|
||||
``` go
|
||||
func BenchmarkRepeat(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
Repeat("a")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Following command runs benchmarks:
|
||||
|
||||
``` shell
|
||||
go test -bench=.
|
||||
```
|
||||
|
||||
# Tools
|
||||
|
||||
## Coverage
|
||||
|
||||
[Coverage](https://blog.golang.org/cover) is built in as well:
|
||||
|
||||
``` shell
|
||||
go test -cover
|
||||
```
|
||||
|
||||
## Race conditions
|
||||
|
||||
In Go you can detect race conditions by adding the `-race` argument:
|
||||
|
||||
``` shell
|
||||
go test -race
|
||||
```
|
||||
|
||||
# DeepEqual
|
||||
|
||||
For \`slices\` & friends you can use \`reflect.DeepEqual\` to compare
|
||||
variables in tests
|
||||
|
||||
``` go
|
||||
func TestSumAll(t *testing.T) {
|
||||
|
||||
got := SumAll([]int{1, 2}, []int{0, 9})
|
||||
want := []int{3, 9}
|
||||
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("got %v want %v", got, want)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# TableDrivenTests
|
||||
|
||||
Writing good tests is not trivial, but in many situations a lot of
|
||||
ground can be covered with [table-driven
|
||||
tests](https://github.com/golang/go/wiki/TableDrivenTests): Each table
|
||||
entry is a complete test case with inputs and expected results, and
|
||||
sometimes with additional information such as a test name to make the
|
||||
test output easily readable. If you ever find yourself using copy and
|
||||
paste when writing a test, think about whether refactoring into a
|
||||
table-driven test or pulling the copied code out into a helper function
|
||||
might be a better option.
|
||||
|
||||
Given a table of test cases, the actual test simply iterates through all
|
||||
table entries and for each entry performs the necessary tests. The test
|
||||
code is written once and amortized over all table entries, so it makes
|
||||
sense to write a careful test with good error messages.
|
||||
|
||||
``` go
|
||||
var flagtests = []struct {
|
||||
in string
|
||||
out string
|
||||
}{
|
||||
{"%a", "[%a]"},
|
||||
{"%-a", "[%-a]"},
|
||||
{"%+a", "[%+a]"},
|
||||
{"%#a", "[%#a]"},
|
||||
{"% a", "[% a]"},
|
||||
{"%0a", "[%0a]"},
|
||||
{"%1.2a", "[%1.2a]"},
|
||||
{"%-1.2a", "[%-1.2a]"},
|
||||
{"%+1.2a", "[%+1.2a]"},
|
||||
{"%-+1.2a", "[%+-1.2a]"},
|
||||
{"%-+1.2abc", "[%+-1.2a]bc"},
|
||||
{"%-1.2abc", "[%-1.2a]bc"},
|
||||
}
|
||||
func TestFlagParser(t *testing.T) {
|
||||
var flagprinter flagPrinter
|
||||
for _, tt := range flagtests {
|
||||
t.Run(tt.in, func(t *testing.T) {
|
||||
s := Sprintf(tt.in, &flagprinter)
|
||||
if s != tt.out {
|
||||
t.Errorf("got %q, want %q", s, tt.out)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# Fatals
|
||||
|
||||
Sometimes you want to throw fatal errors in tests to prevent problems,
|
||||
for example in case \`nil\` is returned and you need to do stuff with
|
||||
the return value in later tests:
|
||||
|
||||
``` go
|
||||
func assertError(t *testing.T, got error, want error) {
|
||||
t.Helper()
|
||||
if got == nil {
|
||||
t.Fatal("didn't get an error but wanted one")
|
||||
}
|
||||
|
||||
if got != want {
|
||||
t.Errorf("got %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# Handy packages
|
||||
|
||||
- httptest[^1]
|
||||
- quick[^2]
|
||||
|
||||
# Footnotes
|
||||
|
||||
[^1]: <https://golang.org/pkg/net/http/httptest/>
|
||||
|
||||
[^2]: <https://golang.org/pkg/testing/quick/>
|
44
content/wiki/20200826191508-tooling.md
Normal file
44
content/wiki/20200826191508-tooling.md
Normal file
|
@ -0,0 +1,44 @@
|
|||
---
|
||||
date: 2020-08-26
|
||||
id: a8b17c59-bf17-4dc8-a0cd-5bf68b2e15c1
|
||||
title: Golang tooling
|
||||
---
|
||||
|
||||
# Documentation
|
||||
|
||||
Install godoc with `go get golang.org/x/tools/cmd/godoc`
|
||||
|
||||
Documentation can be generated with
|
||||
|
||||
``` shell
|
||||
godoc --http :8000
|
||||
```
|
||||
|
||||
# Linters
|
||||
|
||||
- [errcheck](https://github.com/kisielk/errcheck)
|
||||
|
||||
# Testing
|
||||
|
||||
## Code coverage
|
||||
|
||||
``` shell
|
||||
go test -cover
|
||||
```
|
||||
|
||||
## Race conditions
|
||||
|
||||
``` shell
|
||||
go test -race
|
||||
```
|
||||
|
||||
## Vetting
|
||||
|
||||
Vet examines Go source code and reports suspicious constructs, such as
|
||||
Printf calls whose arguments do not align with the format string. Vet
|
||||
uses heuristics that do not guarantee all reports are genuine problems,
|
||||
but it can find errors not caught by the compilers.
|
||||
|
||||
``` shell
|
||||
go vet
|
||||
```
|
29
content/wiki/20200826201029-arrays.md
Normal file
29
content/wiki/20200826201029-arrays.md
Normal file
|
@ -0,0 +1,29 @@
|
|||
---
|
||||
date: 2020-08-26
|
||||
id: e7ed8c3a-ee07-4d46-ace9-f354ee4a47b2
|
||||
title: JavaScript Arrays
|
||||
---
|
||||
|
||||
- [Array Prototype
|
||||
Methods](20201009090331-javascript_array_prototype_methods)
|
||||
- [Array Functions](20201113103917-javascript_array_functions)
|
||||
- [Destructuring Arrays](20201103111509-destructuring_arrays)
|
||||
|
||||
# Syntax
|
||||
|
||||
``` javascript
|
||||
let listOfNumbers = [2, 3, 5, 7, 11];
|
||||
console.log(listOfNumbers[2]); // 5
|
||||
console.log(listOfNumbers[0]); // 2
|
||||
```
|
||||
|
||||
# Type
|
||||
|
||||
In JavaScript arrays are a type of [object](20200826201605-objects) that
|
||||
store sequences of things. `typeof` wil therefore return "object"
|
||||
|
||||
``` javascript
|
||||
let listOfThings = ["Car", "Mr Magoo", 42];
|
||||
|
||||
console.log(typeof listOfThings); // object
|
||||
```
|
16
content/wiki/20200826201605-objects.md
Normal file
16
content/wiki/20200826201605-objects.md
Normal file
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
date: 2020-08-26
|
||||
id: 18736297-fc4f-450c-be78-a13770d2c1c1
|
||||
title: JavaScript Objects
|
||||
---
|
||||
|
||||
- [Object Properties](20201113091110-javascript_object_properties)
|
||||
- [Prototypes](20201113091424-javascript_prototypes)
|
||||
- [Object Prototype
|
||||
Methods](20201113093204-javascript_object_prototype_methods)
|
||||
- [Object Keywords](20201113093613-javascript_object_keywords)
|
||||
- [Object Operators](20201113090050-javascript_object_operators)
|
||||
- [Object Functions](20200826201959-object_functions)
|
||||
- [Object Mutability](20200826201737-mutability)
|
||||
- [Object Operators](20201113090050-javascript_object_operators)
|
||||
- [Destructuring Objects](20201103111746-destructuring_objects)
|
35
content/wiki/20200826201737-mutability.md
Normal file
35
content/wiki/20200826201737-mutability.md
Normal file
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
date: 2020-08-26
|
||||
id: fd131977-33f2-42cd-9a3b-46ffd58b9e43
|
||||
title: JavaScript Object Mutability
|
||||
---
|
||||
|
||||
# Description
|
||||
|
||||
With objects, there is a difference between having two references to the
|
||||
same object and having two different objects that contain the same
|
||||
properties.
|
||||
|
||||
# Examples
|
||||
|
||||
``` javascript
|
||||
let object1 = {value: 10};
|
||||
let object2 = object1;
|
||||
let object3 = {value: 10};
|
||||
|
||||
console.log(object1 == object2); // true
|
||||
console.log(object1 == object3); // false
|
||||
|
||||
object1.value = 15;
|
||||
console.log(object2.value); // 15
|
||||
console.log(object3.value); // 10
|
||||
```
|
||||
|
||||
\`const\` objects can have their values changed
|
||||
|
||||
``` javascript
|
||||
const score = { visitors: 0, home: 1 };
|
||||
score.visitors = 23;
|
||||
|
||||
console.log(score); // { visitors: 23, home: 1 }
|
||||
```
|
32
content/wiki/20200826201856-object_operators.md
Normal file
32
content/wiki/20200826201856-object_operators.md
Normal file
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
date: 2020-08-26
|
||||
id: 7b46ba87-7328-479c-8d79-badb24ed7b19
|
||||
title: JavaScript object operators
|
||||
---
|
||||
|
||||
# Delete operator
|
||||
|
||||
The `delete` operator deletes a binding (duh)
|
||||
|
||||
``` javascript
|
||||
let anObject = {left: 1, right: 2};
|
||||
console.log(anObject.left);
|
||||
delete anObject.left;
|
||||
console.log(anObject.left);
|
||||
console.log("left" in anObject);
|
||||
console.log("right" in anObject);
|
||||
```
|
||||
|
||||
# In operator
|
||||
|
||||
The `in` operator tells you whether and object has a property with that
|
||||
name
|
||||
|
||||
``` javascript
|
||||
let Object = {
|
||||
thisPropertyExists: true
|
||||
}
|
||||
|
||||
console.log("thisPropertyExists" in Object)
|
||||
console.log("thisPropertyDoesNotExist" in Object)
|
||||
```
|
19
content/wiki/20200826201959-object_functions.md
Normal file
19
content/wiki/20200826201959-object_functions.md
Normal file
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
date: 2020-08-26
|
||||
id: 1d12fe9c-f655-49d2-8745-3148ec03cef9
|
||||
title: JavaScript Object Functions
|
||||
---
|
||||
|
||||
- [Object.keys](20201113095226-object_keys)
|
||||
|
||||
- [Object.assign](20201113095244-object_assign)
|
||||
|
||||
- [Object.is](20201113095300-object_is)
|
||||
|
||||
- [Object.entries](20201113102048-object_entries)
|
||||
|
||||
- [Object.values](20201113102106-object_values)
|
||||
|
||||
- [Object.getOwnPropertyDescriptors](20201113102125-object_getownpropertydescriptors)
|
||||
|
||||
- [Object.fromEntries](20201116095124-object_fromentries)
|
85
content/wiki/20200827142818-higher_order_functions.md
Normal file
85
content/wiki/20200827142818-higher_order_functions.md
Normal file
|
@ -0,0 +1,85 @@
|
|||
---
|
||||
date: 2020-08-27
|
||||
id: 513ff88e-d0c9-41d1-8416-57a4aff100c7
|
||||
title: JavaScript higher-order functions
|
||||
---
|
||||
|
||||
# Examples
|
||||
|
||||
Functions that operate on other functions, either by taking them as
|
||||
arguments or by returning them, are called higher-order functions. They
|
||||
allow us to abstract over actions as well as values. There are several
|
||||
types, here are some examples.
|
||||
|
||||
## Functions that create new functions
|
||||
|
||||
``` javascript
|
||||
function greaterThan(n) {
|
||||
return m => m > n;
|
||||
}
|
||||
let greaterThan10 = greaterThan(10);
|
||||
console.log(greaterThan10(11));
|
||||
```
|
||||
|
||||
## Functions that change other functions
|
||||
|
||||
``` javascript
|
||||
function noisy(f) {
|
||||
return (...args) => {
|
||||
console.log("calling with", args);
|
||||
let result = f(...args);
|
||||
console.log("called with", args, ", returned", result);
|
||||
return result;
|
||||
};
|
||||
}
|
||||
noisy(Math.min)(3, 2, 1);
|
||||
```
|
||||
|
||||
## Functions that provide new types of flow control
|
||||
|
||||
``` javascript
|
||||
function unless(test, then) {
|
||||
if (!test) then();
|
||||
}
|
||||
|
||||
repeat(3, n => {
|
||||
unless(n % 2 == 1, () => {
|
||||
console.log(n, "is even");
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## ES6
|
||||
|
||||
### Funciton properties
|
||||
|
||||
1. name
|
||||
|
||||
The `name` property contains the function's name:
|
||||
|
||||
``` javascript
|
||||
function foo() {};
|
||||
console.log(foo.name); // foo
|
||||
|
||||
let func1 = function () {};
|
||||
console.log(func1.name); // func1
|
||||
|
||||
let func4;
|
||||
func4 = function () {};
|
||||
console.log(func4.name); // func4
|
||||
```
|
||||
|
||||
1. Default values
|
||||
|
||||
``` javascript
|
||||
let [func1 = function () {}] = [];
|
||||
console.log(func1.name); // func1
|
||||
|
||||
let { f2: func2 = function () {} } = {};
|
||||
console.log(func2.name); // func2
|
||||
|
||||
function g(func3 = function () {}) {
|
||||
return func3.name;
|
||||
}
|
||||
console.log(g()); // func3
|
||||
```
|
72
content/wiki/20200827170931-functions_macros.md
Normal file
72
content/wiki/20200827170931-functions_macros.md
Normal file
|
@ -0,0 +1,72 @@
|
|||
---
|
||||
date: 2020-08-27
|
||||
id: 1324afaa-085a-401c-9757-df93b6c51423
|
||||
title: Rust functions
|
||||
---
|
||||
|
||||
# Functions
|
||||
|
||||
## Case
|
||||
|
||||
Rust uses [snake case](https://en.wikipedia.org/wiki/Snake_case) for
|
||||
function and variable names. Functions always start with fn
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
|
||||
another_function();
|
||||
}
|
||||
|
||||
fn another_function() {
|
||||
println!("Another function.");
|
||||
}
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
In rust you **must** declare parameter types
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
another_function(5);
|
||||
}
|
||||
|
||||
fn another_function(x: i32) {
|
||||
println!("The value of x is: {}", x);
|
||||
}
|
||||
```
|
||||
|
||||
## Rust is expressive
|
||||
|
||||
Rust is an expressive language, so you have to do stuff like this:
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let _x = 5;
|
||||
|
||||
let y = {
|
||||
let x = 3;
|
||||
x + 1
|
||||
};
|
||||
|
||||
println!("The value of y is: {}", y);
|
||||
}
|
||||
```
|
||||
|
||||
## Return values
|
||||
|
||||
Unless you add a return statement, most functions return the last
|
||||
expression implicitly:
|
||||
|
||||
``` rust
|
||||
fn five() -> i32 {
|
||||
5
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = five();
|
||||
|
||||
println!("The value of x is: {}", x);
|
||||
}
|
||||
```
|
66
content/wiki/20200827171036-tooling.md
Normal file
66
content/wiki/20200827171036-tooling.md
Normal file
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
date: 2020-08-27
|
||||
id: 33187ecc-81fd-4136-ad10-b69e8463bd6d
|
||||
title: Rust tooling
|
||||
---
|
||||
|
||||
# Rustc
|
||||
|
||||
Rustc handles Rust compilation `rustc main.rs`
|
||||
|
||||
# Cargo
|
||||
|
||||
Cargo is Rust's build system and package manager
|
||||
|
||||
## Cargo commands
|
||||
|
||||
### Create project
|
||||
|
||||
``` shell
|
||||
cargo new hello_cargo
|
||||
```
|
||||
|
||||
### Build project
|
||||
|
||||
``` shell
|
||||
cargo build
|
||||
```
|
||||
|
||||
### Build & run project
|
||||
|
||||
``` shell
|
||||
cargo run
|
||||
```
|
||||
|
||||
1. Backtrace
|
||||
|
||||
When you want to see an error backtrace set the `RUST_BACKTRACE`
|
||||
environment variable:
|
||||
|
||||
``` shell
|
||||
RUST_BACKTRACE=1 cargo run
|
||||
```
|
||||
|
||||
### Check code
|
||||
|
||||
``` shell
|
||||
cargo check
|
||||
```
|
||||
|
||||
### Build for release
|
||||
|
||||
``` shell
|
||||
cargo build --release
|
||||
```
|
||||
|
||||
## Cargo.toml
|
||||
|
||||
``` toml
|
||||
[package]
|
||||
name = "hello_cargo"
|
||||
version = "0.1.0"
|
||||
authors = ["Your Name <you@example.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
```
|
28
content/wiki/20200827171318-rust_books.md
Normal file
28
content/wiki/20200827171318-rust_books.md
Normal file
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
date: 2020-08-27
|
||||
id: d1b696d7-2dfa-4b0c-b312-f3762b9ae020
|
||||
title: Rust books & exercises
|
||||
---
|
||||
|
||||
# Books
|
||||
|
||||
- The Rust Programming Language[^1]
|
||||
- The Rust Performance Book[^2]
|
||||
- Rust by example[^3]
|
||||
- Rustonomicon[^4]
|
||||
|
||||
# Exercises
|
||||
|
||||
- Rustlings[^5]
|
||||
|
||||
# Footnotes
|
||||
|
||||
[^1]: <https://doc.rust-lang.org/stable/book/title-page.html>
|
||||
|
||||
[^2]: <https://nnethercote.github.io/perf-book/>
|
||||
|
||||
[^3]: <https://doc.rust-lang.org/stable/rust-by-example/>
|
||||
|
||||
[^4]: <https://doc.rust-lang.org/nomicon/>
|
||||
|
||||
[^5]: <https://github.com/rust-lang/rustlings>
|
152
content/wiki/20200827171554-variables_in_rust.md
Normal file
152
content/wiki/20200827171554-variables_in_rust.md
Normal file
|
@ -0,0 +1,152 @@
|
|||
---
|
||||
date: 2020-08-27
|
||||
id: 9a604084-80a1-4868-be7b-950e7f43b65d
|
||||
title: Rust variables
|
||||
---
|
||||
|
||||
# Mutability
|
||||
|
||||
By default variables in Rust are immutable. To make a variable mutable
|
||||
one must explicity add \`mut\` in front of it
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let mut x = 5;
|
||||
println!("The value of x is: {}", x);
|
||||
x = 6;
|
||||
println!("The value of x is: {}", x);
|
||||
}
|
||||
```
|
||||
|
||||
# Constants
|
||||
|
||||
Constatns are values that are bound to a name and are not allowed to
|
||||
change. Some differences with variables:
|
||||
|
||||
- You can't use \`mut\` with constants
|
||||
- Constants are delared with \`const\` keyword instead of \`let\`
|
||||
- Type value must be annotated
|
||||
- Constants can be declared in any scope
|
||||
- Constants may only be set to a constant expression, not the result
|
||||
of a function call of any other value that could only be computed at
|
||||
runtime
|
||||
|
||||
``` rust
|
||||
#![allow(unused_variables)]
|
||||
fn main() {
|
||||
const MAX_POINTS: u32 = 100_000;
|
||||
}
|
||||
```
|
||||
|
||||
# Shadowing
|
||||
|
||||
You can declare a new variable with the same value as a previous
|
||||
variable. The new variable "shadows" the previous variable
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let x = 5;
|
||||
|
||||
let x = x + 1;
|
||||
|
||||
let x = x * 2;
|
||||
|
||||
println!("The value of x is: {}", x);
|
||||
}
|
||||
```
|
||||
|
||||
Shadowing is different from marking a variable as mut, because we’ll get
|
||||
a compile-time error if we accidentally try to reassign to this variable
|
||||
without using the let keyword. By using let, we can perform a few
|
||||
transformations on a value but have the variable be immutable after
|
||||
those transformations have been completed.
|
||||
|
||||
The other difference between mut and shadowing is that because we’re
|
||||
effectively creating a new variable when we use the let keyword again,
|
||||
we can change the type of the value but reuse the same name. For
|
||||
example, say our program asks a user to show how many spaces they want
|
||||
between some text by inputting space characters, but we really want to
|
||||
store that input as a number:
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let spaces = " ";
|
||||
let spaces = spaces.len();
|
||||
|
||||
println!("There are {} spaces in the string", spaces)
|
||||
}
|
||||
```
|
||||
|
||||
# Data types
|
||||
|
||||
## Tuple
|
||||
|
||||
Tuple elements can be accessed directly by using a period.
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let tup: (i32, f64, u8) = (500, 6.4, 1);
|
||||
|
||||
println!("These are the tuple values {} {} {}", tup.0, tup.1, tup.2)
|
||||
}
|
||||
```
|
||||
|
||||
## Array
|
||||
|
||||
In Rust every element of an array must have the same type. They also
|
||||
have a fixed length, like tuples.
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let _a = [1, 2, 3, 4, 5];
|
||||
}
|
||||
```
|
||||
|
||||
You would write an array’s type by using square brackets, and within the
|
||||
brackets include the type of each element, a semicolon, and then the
|
||||
number of elements in the array, like so:
|
||||
|
||||
``` rust
|
||||
#![allow(unused_variables)]
|
||||
fn main() {
|
||||
let a: [i32; 5] = [1, 2, 3, 4, 5];
|
||||
}
|
||||
```
|
||||
|
||||
You can also easily initialize an array that contains the same value for
|
||||
each element:
|
||||
|
||||
``` rust
|
||||
#![allow(unused_variables)]
|
||||
fn main() {
|
||||
let a = [3; 5];
|
||||
}
|
||||
```
|
||||
|
||||
Accessing array elements is also straightforward:
|
||||
|
||||
``` rust
|
||||
#![allow(unused_variables)]
|
||||
fn main() {
|
||||
let a = [1, 2, 3, 4, 5];
|
||||
|
||||
let first = a[0];
|
||||
let second = a[1];
|
||||
}
|
||||
```
|
||||
|
||||
## Destructuring
|
||||
|
||||
Rust also supports destructuring
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let tup = (500, 6.4, 1);
|
||||
|
||||
let (x, y, z) = tup;
|
||||
|
||||
println!("The value of x is: {}", x);
|
||||
println!("The value of y is: {}", y);
|
||||
println!("The value of z is: {}", z);
|
||||
}
|
||||
```
|
114
content/wiki/20200827190035-rust_comments.md
Normal file
114
content/wiki/20200827190035-rust_comments.md
Normal file
|
@ -0,0 +1,114 @@
|
|||
---
|
||||
date: 2020-08-27
|
||||
id: f4c04f44-c7c3-4fa0-a4d6-e78995257b9c
|
||||
title: Rust Comments
|
||||
---
|
||||
|
||||
# Basics
|
||||
|
||||
In Rust, the idiomatic comment style starts a comment with two slashes,
|
||||
and the comment continues until the end of the line. For comments that
|
||||
extend beyond a single line, you’ll need to include // on each line,
|
||||
like this:
|
||||
|
||||
``` rust
|
||||
// So we’re doing something complicated here, long enough that we need
|
||||
// multiple lines of comments to do it! Whew! Hopefully, this comment will
|
||||
// explain what’s going on.
|
||||
```
|
||||
|
||||
Comments can also be placed at the end of lines containing code:
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
println!("tralala") // This prints something
|
||||
}
|
||||
```
|
||||
|
||||
But if you're a sane person you'll comment above the code you're
|
||||
annotating
|
||||
|
||||
``` rust
|
||||
// This prints something
|
||||
fn main() {
|
||||
println!("tralala")
|
||||
}
|
||||
```
|
||||
|
||||
# Documentation comments
|
||||
|
||||
## */*
|
||||
|
||||
This is like phpdoc, but for Rust. Documentation comments use three
|
||||
slashes `///` and support Markdown notation:
|
||||
|
||||
``` rust
|
||||
/// Adds one to the number given.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let arg = 5;
|
||||
/// let answer = my_crate::add_one(arg);
|
||||
///
|
||||
/// assert_eq!(6, answer);
|
||||
/// ```
|
||||
pub fn add_one(x: i32) -> i32 {
|
||||
x + 1
|
||||
}
|
||||
```
|
||||
|
||||
Run `cargo doc` to generate HTML documentation from the comments.
|
||||
`cargo doc --open` will open documentation in the browser.
|
||||
|
||||
### Commonly used sections
|
||||
|
||||
1. Panics
|
||||
|
||||
The scenarios in which the function being documented could panic.
|
||||
Callers of the function who don’t want their programs to panic
|
||||
should make sure they don’t call the function in these situations.
|
||||
|
||||
2. Errors
|
||||
|
||||
If the function returns a `Result`, describing the kinds of errors
|
||||
that might occur and what conditions might cause those errors to be
|
||||
returned can be helpful to callers so they can write code to handle
|
||||
the different kinds of errors in different ways.
|
||||
|
||||
3. Safety
|
||||
|
||||
If the function is `unsafe` to call, there should be a section
|
||||
explaining why the function is unsafe and covering the invariants
|
||||
that the function expects callers to uphold.
|
||||
|
||||
## //!
|
||||
|
||||
This is used for general comments:
|
||||
|
||||
``` rust
|
||||
//! # My Crate
|
||||
//!
|
||||
//! `my_crate` is a collection of utilities to make performing certain
|
||||
//! calculations more convenient.
|
||||
|
||||
/// Adds one to the number given.
|
||||
// --snip--
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let arg = 5;
|
||||
/// let answer = my_crate::add_one(arg);
|
||||
///
|
||||
/// assert_eq!(6, answer);
|
||||
/// ```
|
||||
pub fn add_one(x: i32) -> i32 {
|
||||
x + 1
|
||||
}
|
||||
```
|
||||
|
||||
# Changes
|
||||
|
||||
- [Linking To Items By Name](20201119170237-linking_to_items_by_name)
|
||||
- [Search Aliases](20201119170710-search_aliases)
|
97
content/wiki/20200827190443-rust_control_flow.md
Normal file
97
content/wiki/20200827190443-rust_control_flow.md
Normal file
|
@ -0,0 +1,97 @@
|
|||
---
|
||||
date: 2020-08-27
|
||||
id: 0ae97b2d-5a3c-40b5-9ce1-37aacb647c5d
|
||||
title: Rust control flow
|
||||
---
|
||||
|
||||
# Branching
|
||||
|
||||
## If
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let number = 3;
|
||||
|
||||
if number < 5 {
|
||||
println!("condition was true");
|
||||
} else {
|
||||
println!("condition was false");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Because Rust is expressive we can use an \`if\` expression on the right
|
||||
side of a \`let\` statement:
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let condition = true;
|
||||
let number = if condition { 5 } else { 6 };
|
||||
|
||||
println!("The value of number is: {}", number);
|
||||
}
|
||||
```
|
||||
|
||||
# Loops
|
||||
|
||||
## Loop
|
||||
|
||||
This will loop forever
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
loop {
|
||||
println!("again!");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Loops can also return values:
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let mut counter = 0;
|
||||
|
||||
let result = loop {
|
||||
counter += 1;
|
||||
|
||||
if counter == 10 {
|
||||
break counter * 2;
|
||||
}
|
||||
};
|
||||
|
||||
println!("The result is {}", result);
|
||||
}
|
||||
```
|
||||
|
||||
## While
|
||||
|
||||
Rust also supports while loops:
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let mut number = 3;
|
||||
|
||||
while number != 0 {
|
||||
println!("{}!", number);
|
||||
|
||||
number -= 1;
|
||||
}
|
||||
|
||||
println!("LIFTOFF!!!");
|
||||
}
|
||||
```
|
||||
|
||||
## For
|
||||
|
||||
For loops are supported as well
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let a = [10, 20, 30, 40, 50];
|
||||
|
||||
for element in a.iter() {
|
||||
println!("the value is: {}", element);
|
||||
}
|
||||
}
|
||||
```
|
7
content/wiki/20200828170945-ownership.md
Normal file
7
content/wiki/20200828170945-ownership.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
date: 2020-08-28
|
||||
id: e51ace6b-e3ca-4e83-aa11-80848204bd68
|
||||
title: Ownership in Rust
|
||||
---
|
||||
|
||||
TODO. Can't be bothered to write this now
|
53
content/wiki/20200828180957-pointers.md
Normal file
53
content/wiki/20200828180957-pointers.md
Normal file
|
@ -0,0 +1,53 @@
|
|||
---
|
||||
date: 2020-08-28
|
||||
id: f2e19e3e-e28a-4998-8b0c-38ebfdb559e5
|
||||
title: Golang Pointers
|
||||
---
|
||||
|
||||
# Basics
|
||||
|
||||
Go also supports pointers. Default value is always NULL and you can't do
|
||||
pointer arithmetic. Other than that, nothing that will blow your mind
|
||||
here.
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
i, j := 42, 2701
|
||||
|
||||
p := &i // point to i
|
||||
fmt.Println(*p) // read i through the pointer
|
||||
*p = 21 // set i through the pointer
|
||||
fmt.Println(i) // see the new value of i
|
||||
|
||||
p = &j // point to j
|
||||
*p = *p / 37 // divide j through the pointer
|
||||
fmt.Println(j) // see the new value of j
|
||||
}
|
||||
```
|
||||
|
||||
# Pointers to [Golang Structs](20200828181259-structs)
|
||||
|
||||
To facilitate lazy people like me Go allows you to lose the \`\*\` when
|
||||
using a pointer to a struct
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Vertex struct {
|
||||
X int
|
||||
Y int
|
||||
}
|
||||
|
||||
func main() {
|
||||
v := Vertex{1, 2}
|
||||
p := &v
|
||||
p.X = 123
|
||||
fmt.Println(v)
|
||||
}
|
||||
```
|
186
content/wiki/20200828181259-structs.md
Normal file
186
content/wiki/20200828181259-structs.md
Normal file
|
@ -0,0 +1,186 @@
|
|||
---
|
||||
date: 2020-08-28
|
||||
id: 463ce364-f426-4089-a0ca-ffe45f0461f2
|
||||
title: Golang Structs
|
||||
---
|
||||
|
||||
# Basics
|
||||
|
||||
Golang structs are what you expect
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Vertex struct {
|
||||
X int
|
||||
Y int
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println(Vertex{1, 2})
|
||||
}
|
||||
```
|
||||
|
||||
# Struct fields
|
||||
|
||||
Struct fields are accessed using a dot
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Coorindate struct {
|
||||
X int
|
||||
Y int
|
||||
}
|
||||
|
||||
func main() {
|
||||
coordinate := Coorindate{1, 67}
|
||||
coordinate.X = 26
|
||||
fmt.Println(coordinate.X)
|
||||
}
|
||||
```
|
||||
|
||||
# Struct literals
|
||||
|
||||
You can also newly allocate a struct by listing the values of its
|
||||
fields. This is known as a "struct literal" (duh)
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Vertex struct {
|
||||
X, Y int
|
||||
}
|
||||
|
||||
var (
|
||||
v1 = Vertex{1, 2} // has type Vertex
|
||||
v2 = Vertex{X: 1} // Y:0 is implicit
|
||||
v3 = Vertex{} // X:0 and Y:0
|
||||
p = &Vertex{1, 2} // has type *Vertex
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(v1, p, v2, v3)
|
||||
}
|
||||
```
|
||||
|
||||
# Struct tags
|
||||
|
||||
[Struct tags](https://go.dev/wiki/Well-known-struct-tags) allow other
|
||||
modules accessing struct members to format member values.
|
||||
|
||||
## Control encoding
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Name string `json:"name"`
|
||||
Password string `json:"password"`
|
||||
PreferredFish []string `json:"preferredFish"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
u := &User{
|
||||
Name: "Sammy the Shark",
|
||||
Password: "fisharegreat",
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
|
||||
out, err := json.MarshalIndent(u, "", " ")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Println(string(out))
|
||||
}
|
||||
```
|
||||
|
||||
## Remove empty fields
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Name string `json:"name"`
|
||||
Password string `json:"password"`
|
||||
PreferredFish []string `json:"preferredFish,omitempty"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
u := &User{
|
||||
Name: "Sammy the Shark",
|
||||
Password: "fisharegreat",
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
|
||||
out, err := json.MarshalIndent(u, "", " ")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Println(string(out))
|
||||
}
|
||||
```
|
||||
|
||||
## Ignore private fields
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Name string `json:"name"`
|
||||
Password string `json:"-"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
u := &User{
|
||||
Name: "Sammy the Shark",
|
||||
Password: "fisharegreat",
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
|
||||
out, err := json.MarshalIndent(u, "", " ")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Println(string(out))
|
||||
}
|
||||
```
|
26
content/wiki/20200828182327-arrays.md
Normal file
26
content/wiki/20200828182327-arrays.md
Normal file
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
date: 2020-08-28
|
||||
id: 24d46884-652c-4b64-b8e1-1baf81bea0f4
|
||||
title: Golang Arrays
|
||||
---
|
||||
|
||||
Arrays are a thing in Go as well. Once initialized arrays cannot be
|
||||
resized, if you're into **that** type of thing (no judgement) see
|
||||
[slices](20200828182546-slices)
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
var a [2]string
|
||||
a[0] = "Hello"
|
||||
a[1] = "World"
|
||||
fmt.Println(a[0], a[1])
|
||||
fmt.Println(a)
|
||||
|
||||
primes := [6]int{2, 3, 5, 7, 11, 13}
|
||||
fmt.Println(primes)
|
||||
}
|
||||
```
|
290
content/wiki/20200828182546-slices.md
Normal file
290
content/wiki/20200828182546-slices.md
Normal file
|
@ -0,0 +1,290 @@
|
|||
---
|
||||
date: 2020-08-28
|
||||
id: 8b5fb822-d1ad-46de-9299-37e3d3f5108c
|
||||
title: Golang slices
|
||||
---
|
||||
|
||||
# Basics
|
||||
|
||||
A slice is a dynamically sized, flexible view into the elements of an
|
||||
array. Apparently they are much more common than arrays. Initialization
|
||||
is pretty straight forward:
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
primes := [6]int{2, 3, 5, 7, 11, 13}
|
||||
|
||||
var s []int = primes[1:4]
|
||||
fmt.Println(s)
|
||||
}
|
||||
```
|
||||
|
||||
Slices are like references. Change something in the slice and the
|
||||
[array](20200828182327-arrays) it references also changes
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
names := [4]string{
|
||||
"John",
|
||||
"Paul",
|
||||
"George",
|
||||
"Ringo",
|
||||
}
|
||||
fmt.Println(names)
|
||||
|
||||
a := names[0:2]
|
||||
b := names[1:3]
|
||||
fmt.Println(a, b)
|
||||
|
||||
b[0] = "XXX"
|
||||
fmt.Println(a, b)
|
||||
fmt.Println(names)
|
||||
}
|
||||
```
|
||||
|
||||
Slices can contain any type, including other slices:
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Create a tic-tac-toe board.
|
||||
board := [][]string{
|
||||
[]string{"_", "_", "_"},
|
||||
[]string{"_", "_", "_"},
|
||||
[]string{"_", "_", "_"},
|
||||
}
|
||||
|
||||
// The players take turns.
|
||||
board[0][0] = "X"
|
||||
board[2][2] = "O"
|
||||
board[1][2] = "X"
|
||||
board[1][0] = "O"
|
||||
board[0][2] = "X"
|
||||
|
||||
for i := 0; i < len(board); i++ {
|
||||
fmt.Printf("%s\n", strings.Join(board[i], " "))
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
# Slice literals
|
||||
|
||||
A slice literal is like an array, but without the length, so we add more
|
||||
stuff to it later
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
q := []int{2, 3, 5, 7, 11, 13}
|
||||
fmt.Println(q)
|
||||
|
||||
r := []bool{true, false, true, true, false, true}
|
||||
fmt.Println(r)
|
||||
|
||||
s := []struct {
|
||||
i int
|
||||
b bool
|
||||
}{
|
||||
{2, true},
|
||||
{3, false},
|
||||
{5, true},
|
||||
{7, true},
|
||||
{11, false},
|
||||
{13, true},
|
||||
}
|
||||
fmt.Println(s)
|
||||
}
|
||||
```
|
||||
|
||||
# Slice defaults
|
||||
|
||||
You can omit high and low bounds. As one would expect these default to 0
|
||||
and slice length respectively
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
s := []int{2, 3, 5, 7, 11, 13}
|
||||
|
||||
s = s[1:4]
|
||||
fmt.Println(s)
|
||||
|
||||
s = s[:2]
|
||||
fmt.Println(s)
|
||||
|
||||
s = s[1:]
|
||||
fmt.Println(s)
|
||||
}
|
||||
```
|
||||
|
||||
# Slice length and capacity
|
||||
|
||||
One can lookup slice length (length of the slice) and capacity (length
|
||||
of the array the slice references)
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
s := []int{2, 3, 5, 7, 11, 13}
|
||||
printSlice(s)
|
||||
|
||||
// Slice the slice to give it zero length.
|
||||
s = s[:0]
|
||||
printSlice(s)
|
||||
|
||||
// Extend its length.
|
||||
s = s[:4]
|
||||
printSlice(s)
|
||||
|
||||
// Drop its first two values.
|
||||
s = s[2:]
|
||||
printSlice(s)
|
||||
}
|
||||
|
||||
func printSlice(s []int) {
|
||||
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
|
||||
}
|
||||
```
|
||||
|
||||
# Nil slices
|
||||
|
||||
Empty slices are equal to `nil`. Maybe that's a good idea, maybe it
|
||||
isn't. Typing this i'm too tired to give rational input to this
|
||||
philosophical quagmire.
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
var s []int
|
||||
fmt.Println(s, len(s), cap(s))
|
||||
if s == nil {
|
||||
fmt.Println("nil!")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# Make
|
||||
|
||||
Slices can be created with the `make` function, this way you can treat
|
||||
them like arrays that we know and love.
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
a := make([]int, 5)
|
||||
printSlice("a", a)
|
||||
|
||||
b := make([]int, 0, 5)
|
||||
printSlice("b", b)
|
||||
|
||||
c := b[:2]
|
||||
printSlice("c", c)
|
||||
|
||||
d := c[2:5]
|
||||
printSlice("d", d)
|
||||
}
|
||||
|
||||
func printSlice(s string, x []int) {
|
||||
fmt.Printf("%s len=%d cap=%d %v\n",
|
||||
s, len(x), cap(x), x)
|
||||
}
|
||||
```
|
||||
|
||||
# Append
|
||||
|
||||
New elements can be added to a slice with the
|
||||
[append](https://golang.org/pkg/builtin/#append) function
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
var s []int
|
||||
printSlice(s)
|
||||
|
||||
// append works on nil slices.
|
||||
s = append(s, 0)
|
||||
printSlice(s)
|
||||
|
||||
// The slice grows as needed.
|
||||
s = append(s, 1)
|
||||
printSlice(s)
|
||||
|
||||
// We can add more than one element at a time.
|
||||
s = append(s, 2, 3, 4)
|
||||
printSlice(s)
|
||||
}
|
||||
|
||||
func printSlice(s []int) {
|
||||
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
|
||||
}
|
||||
```
|
||||
|
||||
# Range
|
||||
|
||||
You can iterate over slices with `range`
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
|
||||
|
||||
func main() {
|
||||
for i, v := range pow {
|
||||
fmt.Printf("2**%d = %d\n", i, v)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Index or value can be skipped by using `_`. In case you only want the
|
||||
index, just omit the second variable entirely:
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
pow := make([]int, 10)
|
||||
for i := range pow {
|
||||
pow[i] = 1 << uint(i) // == 2**i
|
||||
}
|
||||
for _, value := range pow {
|
||||
fmt.Printf("%d\n", value)
|
||||
}
|
||||
}
|
||||
```
|
126
content/wiki/20200828192034-maps.md
Normal file
126
content/wiki/20200828192034-maps.md
Normal file
|
@ -0,0 +1,126 @@
|
|||
---
|
||||
date: 2020-08-28
|
||||
id: 85fe90d9-f7d2-47fb-9471-f2557b1fa95d
|
||||
title: Golang maps
|
||||
---
|
||||
|
||||
# Basics
|
||||
|
||||
A map maps keys to values, ie: associative arrays. Zero value of a map
|
||||
is `nil`. `make` function returns a new `map`.
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Vertex struct {
|
||||
Lat, Long float64
|
||||
}
|
||||
|
||||
var m map[string]Vertex
|
||||
|
||||
func main() {
|
||||
m = make(map[string]Vertex)
|
||||
m["Bell Labs"] = Vertex{
|
||||
40.68433, -74.39967,
|
||||
}
|
||||
fmt.Println(m["Bell Labs"])
|
||||
}
|
||||
```
|
||||
|
||||
# Map literals
|
||||
|
||||
These are essentially the same as [struct
|
||||
literals](20200828181259-structs), keys are required.
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Vertex struct {
|
||||
Lat, Long float64
|
||||
}
|
||||
|
||||
var m = map[string]Vertex{
|
||||
"Bell Labs": Vertex{
|
||||
40.68433, -74.39967,
|
||||
},
|
||||
"Google": Vertex{
|
||||
37.42202, -122.08408,
|
||||
},
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println(m)
|
||||
}
|
||||
```
|
||||
|
||||
If top-level type is just a type name, it can be omitted from literal
|
||||
elements. Saves some typing.
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Vertex struct {
|
||||
Lat, Long float64
|
||||
}
|
||||
|
||||
var m = map[string]Vertex{
|
||||
"Bell Labs": {40.68433, -74.39967},
|
||||
"Google": {37.42202, -122.08408},
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println(m)
|
||||
}
|
||||
```
|
||||
|
||||
# Mutating maps
|
||||
|
||||
Nothing shocking here either. Map elements can be
|
||||
added/deleted/modified/etc.
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
m := make(map[string]int)
|
||||
|
||||
m["Answer"] = 42
|
||||
fmt.Println("The value:", m["Answer"])
|
||||
|
||||
m["Answer"] = 48
|
||||
fmt.Println("The value:", m["Answer"])
|
||||
|
||||
delete(m, "Answer")
|
||||
fmt.Println("The value:", m["Answer"])
|
||||
|
||||
v, ok := m["Answer"]
|
||||
fmt.Println("The value:", v, "Present?", ok)
|
||||
}
|
||||
```
|
||||
|
||||
# Types
|
||||
|
||||
A `type` can be declared as a thin wrapper around a `map`:
|
||||
|
||||
``` go
|
||||
import "fmt"
|
||||
|
||||
type Dictionary map[string]string
|
||||
|
||||
func (d Dictionary) Search(word string) string {
|
||||
return d[word]
|
||||
}
|
||||
|
||||
func main() {
|
||||
d := Dictionary{"key": "This is the value"}
|
||||
fmt.Println(d.Search("key"))
|
||||
}
|
||||
```
|
65
content/wiki/20200831155304-methods.md
Normal file
65
content/wiki/20200831155304-methods.md
Normal file
|
@ -0,0 +1,65 @@
|
|||
---
|
||||
date: 2020-08-31
|
||||
id: 03a6cd46-e6fb-46a8-96f7-16c37a6d140a
|
||||
title: Golang methods
|
||||
---
|
||||
|
||||
# Basics
|
||||
|
||||
In Go methods can be defined on [struct](20200828181259-structs) and
|
||||
non-struct types. In this case a **receiver** argument ias passed
|
||||
between \`func\` keyword and the method name (\`Abs\`):
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
type Vertex struct {
|
||||
X, Y float64
|
||||
}
|
||||
|
||||
func (v Vertex) Abs() float64 {
|
||||
return math.Sqrt(v.X*v.X + v.Y*v.Y)
|
||||
}
|
||||
|
||||
func main() {
|
||||
v := Vertex{3, 4}
|
||||
fmt.Println(v.Abs())
|
||||
}
|
||||
```
|
||||
|
||||
# Pointers
|
||||
|
||||
To modify struct values methods must be declared with pointer receivers:
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
type Vertex struct {
|
||||
X, Y float64
|
||||
}
|
||||
|
||||
func (v Vertex) Abs() float64 {
|
||||
return math.Sqrt(v.X*v.X + v.Y*v.Y)
|
||||
}
|
||||
|
||||
func (v *Vertex) Scale(f float64) {
|
||||
v.X = v.X * f
|
||||
v.Y = v.Y * f
|
||||
}
|
||||
|
||||
func main() {
|
||||
v := Vertex{3, 4}
|
||||
v.Scale(10)
|
||||
fmt.Println(v.Abs())
|
||||
}
|
||||
```
|
179
content/wiki/20200831171822-interfaces.md
Normal file
179
content/wiki/20200831171822-interfaces.md
Normal file
|
@ -0,0 +1,179 @@
|
|||
---
|
||||
date: 2020-08-31
|
||||
id: 7ca10187-82d5-44fb-83a2-aa739c14cb24
|
||||
title: Golang interfaces
|
||||
---
|
||||
|
||||
# Basics
|
||||
|
||||
Go supports method interfaces:
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
type Abser interface {
|
||||
Abs() float64
|
||||
}
|
||||
|
||||
func main() {
|
||||
var a Abser
|
||||
f := MyFloat(-math.Sqrt2)
|
||||
v := Vertex{3, 4}
|
||||
|
||||
a = f // a MyFloat implements Abser
|
||||
a = &v // a *Vertex implements Abser
|
||||
|
||||
fmt.Println(a.Abs())
|
||||
}
|
||||
|
||||
type MyFloat float64
|
||||
|
||||
func (f MyFloat) Abs() float64 {
|
||||
if f < 0 {
|
||||
return float64(-f)
|
||||
}
|
||||
return float64(f)
|
||||
}
|
||||
|
||||
type Vertex struct {
|
||||
X, Y float64
|
||||
}
|
||||
|
||||
func (v *Vertex) Abs() float64 {
|
||||
return math.Sqrt(v.X*v.X + v.Y*v.Y)
|
||||
}
|
||||
```
|
||||
|
||||
Interfaces are implemented implicitly:
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type I interface {
|
||||
M()
|
||||
}
|
||||
|
||||
type T struct {
|
||||
S string
|
||||
}
|
||||
|
||||
// This method means type T implements the interface I,
|
||||
// but we don't need to explicitly declare that it does so.
|
||||
func (t T) M() {
|
||||
fmt.Println(t.S)
|
||||
}
|
||||
|
||||
func main() {
|
||||
var i I = T{"hello"}
|
||||
i.M()
|
||||
}
|
||||
```
|
||||
|
||||
# Handy interfaces to know about
|
||||
|
||||
## Stringer
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
func (p Person) String() string {
|
||||
return fmt.Sprintf("%v (%v years)", p.Name, p.Age)
|
||||
}
|
||||
|
||||
func main() {
|
||||
a := Person{"Arthur Dent", 42}
|
||||
z := Person{"Zaphod Beeblebrox", 9001}
|
||||
fmt.Println(a, z)
|
||||
}
|
||||
```
|
||||
|
||||
## Error
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type MyError struct {
|
||||
When time.Time
|
||||
What string
|
||||
}
|
||||
|
||||
func (e *MyError) Error() string {
|
||||
return fmt.Sprintf("at %v, %s",
|
||||
e.When, e.What)
|
||||
}
|
||||
|
||||
func run() error {
|
||||
return &MyError{
|
||||
time.Now(),
|
||||
"it didn't work",
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := run(); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Reader
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
r := strings.NewReader("Hello, Reader!")
|
||||
|
||||
b := make([]byte, 8)
|
||||
for {
|
||||
n, err := r.Read(b)
|
||||
fmt.Printf("n = %v err = %v b = %v\n", n, err, b)
|
||||
fmt.Printf("b[:n] = %q\n", b[:n])
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Images
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
)
|
||||
|
||||
func main() {
|
||||
m := image.NewRGBA(image.Rect(0, 0, 100, 100))
|
||||
fmt.Println(m.Bounds())
|
||||
fmt.Println(m.At(0, 0).RGBA())
|
||||
}
|
||||
```
|
155
content/wiki/20200831193417-structs.md
Normal file
155
content/wiki/20200831193417-structs.md
Normal file
|
@ -0,0 +1,155 @@
|
|||
---
|
||||
date: 2020-08-31
|
||||
id: 26048172-107d-4ad4-9906-acdf7935dfcb
|
||||
title: Rust Structs Syntax
|
||||
---
|
||||
|
||||
# Basics
|
||||
|
||||
``` rust
|
||||
struct User {
|
||||
username: String,
|
||||
email: String,
|
||||
sign_in_count: u64,
|
||||
active: bool,
|
||||
}
|
||||
|
||||
fn build_user(email: String, username: String) -> User {
|
||||
// When struct field name and parameter name are the same shorthand syntax can be used
|
||||
User {
|
||||
email,
|
||||
username,
|
||||
active: true,
|
||||
sign_in_count: 1,
|
||||
}
|
||||
}
|
||||
|
||||
fn print_data(user: User) {
|
||||
println!("User email is: {}", user.email);
|
||||
println!("User username is: {}", user.username);
|
||||
println!("User sign in count is: {}", user.sign_in_count);
|
||||
println!("User active is: {}", user.active);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let user1 = build_user(
|
||||
String::from("someone@example.com"),
|
||||
String::from("someusername123"),
|
||||
);
|
||||
|
||||
println!("User 1");
|
||||
print_data(user1);
|
||||
|
||||
let mut user2 = User {
|
||||
email: String::from("someone@example.com"),
|
||||
username: String::from("someusername123"),
|
||||
active: true,
|
||||
sign_in_count: 1,
|
||||
};
|
||||
user2.email = String::from("anotheremail@example.com");
|
||||
|
||||
println!("User 2");
|
||||
print_data(user2);
|
||||
}
|
||||
```
|
||||
|
||||
``` rust
|
||||
|
||||
```
|
||||
|
||||
# Tuple Struct
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
struct Color(i32, i32, i32);
|
||||
struct Point(i32, i32, i32);
|
||||
|
||||
let black = Color(0, 0, 0);
|
||||
let origin = Point(0, 0, 0);
|
||||
}
|
||||
```
|
||||
|
||||
# Debug trait
|
||||
|
||||
To print out debugging information we have the [debug
|
||||
trait](https://doc.rust-lang.org/std/fmt/trait.Debug.html):
|
||||
|
||||
``` rust
|
||||
#[derive(Debug)]
|
||||
struct Rectangle {
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let rect1 = Rectangle {
|
||||
width: 30,
|
||||
height: 50,
|
||||
};
|
||||
|
||||
println!("rect1 is {:?}", rect1);
|
||||
}
|
||||
```
|
||||
|
||||
# Methods
|
||||
|
||||
Methods are like functions, but for structs:
|
||||
|
||||
``` rust
|
||||
#[derive(Debug)]
|
||||
struct Rectangle {
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
impl Rectangle {
|
||||
fn area(&self) -> u32 {
|
||||
self.width * self.height
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let rect1 = Rectangle {
|
||||
width: 30,
|
||||
height: 50,
|
||||
};
|
||||
|
||||
println!(
|
||||
"The area of the rectangle is {} square pixels.",
|
||||
rect1.area()
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
# Associated Functions
|
||||
|
||||
These are Rust's take on static functions. They **don't** take `self` as
|
||||
a parameter
|
||||
|
||||
``` rust
|
||||
#[derive(Debug)]
|
||||
struct Rectangle {
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
impl Rectangle {
|
||||
fn area(&self) -> u32 {
|
||||
self.width * self.height
|
||||
}
|
||||
fn square(size: u32) -> Rectangle {
|
||||
Rectangle {
|
||||
width: size,
|
||||
height: size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let rect1 = Rectangle::square(10);
|
||||
println!(
|
||||
"The area of the rectangle is {} square pixels.",
|
||||
rect1.area()
|
||||
);
|
||||
}
|
||||
```
|
11
content/wiki/20200901105237-error_handling.md
Normal file
11
content/wiki/20200901105237-error_handling.md
Normal file
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
date: 2020-09-01
|
||||
id: 57c3cee1-22dd-4a11-8a21-a19c571913e9
|
||||
title: JavaScript Error Handling
|
||||
---
|
||||
|
||||
- [Exceptions](20201111092905-javascript_exceptions)
|
||||
- [Error Sub Types](20201111093101-javascript_error_sub_types)
|
||||
- [Strict Mode](20201111092510-javascript_strict_mode)
|
||||
- [Custom Error Types](20201111093651-javascript_custom_error_types)
|
||||
- [Finally](20201111094033-javascript_exceptions_finally)
|
264
content/wiki/20200901141141-goroutines.md
Normal file
264
content/wiki/20200901141141-goroutines.md
Normal file
|
@ -0,0 +1,264 @@
|
|||
---
|
||||
date: 2020-09-01
|
||||
id: 56b6e0d5-090d-4859-9f06-c54a1a116515
|
||||
title: Goroutines
|
||||
---
|
||||
|
||||
# Basics
|
||||
|
||||
A `goroutine` is a lightweight thread managed by the Go runtime.
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func say(s string) {
|
||||
for i := 0; i < 5; i++ {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
fmt.Println(s)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
go say("world")
|
||||
say("hello")
|
||||
}
|
||||
```
|
||||
|
||||
# Channels
|
||||
|
||||
Channels are a typed conduit through whichyou can send and receive
|
||||
values with the channel operator \`\<-\`. By default, sends and receives
|
||||
block until the other side is ready. This allows goroutines to
|
||||
synchronize without explicit locks or condition variables. Channels
|
||||
should generally be used for [passing ownership of
|
||||
data](https://github.com/golang/go/wiki/MutexOrChannel).
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func sum(s []int, c chan int) {
|
||||
sum := 0
|
||||
for _, v := range s {
|
||||
sum += v
|
||||
}
|
||||
c <- sum // send sum to c
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := []int{7, 2, 8, -9, 4, 0}
|
||||
|
||||
c := make(chan int)
|
||||
go sum(s[:len(s)/2], c)
|
||||
go sum(s[len(s)/2:], c)
|
||||
x, y := <-c, <-c // receive from c
|
||||
|
||||
fmt.Println(x, y, x+y)
|
||||
}
|
||||
```
|
||||
|
||||
Channels can also be **buffered**. Provide the buffer length as the
|
||||
second argument to \`make\` to initialize a buffered channel:
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
ch := make(chan int, 2)
|
||||
ch <- 1
|
||||
ch <- 2
|
||||
fmt.Println(<-ch)
|
||||
fmt.Println(<-ch)
|
||||
}
|
||||
```
|
||||
|
||||
Sends to a buffered channel block only when the buffer is full. Receives
|
||||
block when the buffer is empty.
|
||||
|
||||
# Range and close
|
||||
|
||||
A sender can close a channel to indicate that no more values will be
|
||||
sent. Receivers can test whether a channel has been closed by assigning
|
||||
a second parameter to the receive expression.
|
||||
|
||||
Only the sender should close a channel, never the receiver. Sending on a
|
||||
closed channel will cause a panic. Channels aren't like files; you don't
|
||||
usually need to close them. Closing is only necessary when the receiver
|
||||
must be told there are no more values coming, such as to terminate a
|
||||
range loop.
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func fibonacci(n int, c chan int) {
|
||||
x, y := 0, 1
|
||||
for i := 0; i < n; i++ {
|
||||
c <- x
|
||||
x, y = y, x+y
|
||||
}
|
||||
close(c)
|
||||
}
|
||||
|
||||
func main() {
|
||||
c := make(chan int, 10)
|
||||
go fibonacci(cap(c), c)
|
||||
for i := range c {
|
||||
fmt.Println(i)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# Select
|
||||
|
||||
The select statement lets a goroutine wait on multiple communication
|
||||
operations.
|
||||
|
||||
A select blocks until one of its cases can run, then it executes that
|
||||
case. It chooses one at random if multiple are ready.
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func fibonacci(c, quit chan int) {
|
||||
x, y := 0, 1
|
||||
for {
|
||||
select {
|
||||
case c <- x:
|
||||
x, y = y, x+y
|
||||
case <-quit:
|
||||
fmt.Println("quit")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
c := make(chan int)
|
||||
quit := make(chan int)
|
||||
go func() {
|
||||
for i := 0; i < 10; i++ {
|
||||
fmt.Println(<-c)
|
||||
}
|
||||
quit <- 0
|
||||
}()
|
||||
fibonacci(c, quit)
|
||||
}
|
||||
```
|
||||
|
||||
\`default\` case in \`select\` is run if no other case is ready, as one
|
||||
would expect
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
tick := time.Tick(100 * time.Millisecond)
|
||||
boom := time.After(500 * time.Millisecond)
|
||||
for {
|
||||
select {
|
||||
case <-tick:
|
||||
fmt.Println("tick.")
|
||||
case <-boom:
|
||||
fmt.Println("BOOM!")
|
||||
return
|
||||
default:
|
||||
fmt.Println(" .")
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Timeout
|
||||
|
||||
Often you want to set a timeout value for `select` so it won't run
|
||||
forver. [time.After](https://golang.org/pkg/time/#After) is a good way
|
||||
of doing this:
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
var c chan int
|
||||
|
||||
func handle(int) {}
|
||||
|
||||
func main() {
|
||||
select {
|
||||
case m := <-c:
|
||||
handle(m)
|
||||
case <-time.After(10 * time.Second):
|
||||
fmt.Println("timed out")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# sync.Mutex
|
||||
|
||||
TO make sure only one goroutine at a time can access a variable we can
|
||||
use \`sync.Mutex\`
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// SafeCounter is safe to use concurrently.
|
||||
type SafeCounter struct {
|
||||
mu sync.Mutex
|
||||
v map[string]int
|
||||
}
|
||||
|
||||
// Inc increments the counter for the given key.
|
||||
func (c *SafeCounter) Inc(key string) {
|
||||
c.mu.Lock()
|
||||
// Lock so only one goroutine at a time can access the map c.v.
|
||||
c.v[key]++
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
// Value returns the current value of the counter for the given key.
|
||||
func (c *SafeCounter) Value(key string) int {
|
||||
c.mu.Lock()
|
||||
// Lock so only one goroutine at a time can access the map c.v.
|
||||
defer c.mu.Unlock()
|
||||
return c.v[key]
|
||||
}
|
||||
|
||||
func main() {
|
||||
c := SafeCounter{v: make(map[string]int)}
|
||||
for i := 0; i < 1000; i++ {
|
||||
go c.Inc("somekey")
|
||||
}
|
||||
|
||||
time.Sleep(time.Second)
|
||||
fmt.Println(c.Value("somekey"))
|
||||
}
|
||||
```
|
263
content/wiki/20200902150714-enums.md
Normal file
263
content/wiki/20200902150714-enums.md
Normal file
|
@ -0,0 +1,263 @@
|
|||
---
|
||||
date: 2020-09-02
|
||||
id: b95f09af-2cd0-46f2-872e-3cb542d2b2e9
|
||||
title: Rust enums
|
||||
---
|
||||
|
||||
# Basics
|
||||
|
||||
Rust also supports
|
||||
[enums](https://doc.rust-lang.org/rust-by-example/custom_types/enum.html).
|
||||
|
||||
``` rust
|
||||
use std::fmt::Debug;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Message {
|
||||
Write(String),
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let m = Message::Write(String::from("Hello!"));
|
||||
println!("{:?}", m)
|
||||
}
|
||||
```
|
||||
|
||||
# Methods
|
||||
|
||||
As with [structs](20200831193417-structs), methods can be defined as
|
||||
well:
|
||||
|
||||
``` rust
|
||||
use std::fmt::Debug;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Message {
|
||||
Write(String),
|
||||
}
|
||||
|
||||
impl Message {
|
||||
fn call(&self) {
|
||||
println!("tralala");
|
||||
println!("{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let m = Message::Write(String::from("Hello!"));
|
||||
m.call();
|
||||
}
|
||||
```
|
||||
|
||||
# Standard library enums
|
||||
|
||||
## Option
|
||||
|
||||
Instead of \`null\` Rust has the
|
||||
[Option](https://doc.rust-lang.org/std/option/enum.Option.html) enum
|
||||
built in:
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let some_number = Some(5);
|
||||
let some_string = Some("a string");
|
||||
|
||||
let absent_number: Option<i32> = None;
|
||||
}
|
||||
```
|
||||
|
||||
The cool thing about using Option is that \`Option\<T\>\` and \`T\` are
|
||||
different types, therefore the programmer has to define if NULL is
|
||||
acceptable beforehand. The following won't run:
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let x: i8 = 5;
|
||||
let y: Option<i8> = Some(5);
|
||||
|
||||
let sum = x + y;
|
||||
}
|
||||
```
|
||||
|
||||
Huzzah, No more having to worry about incorrectly assuming a not null
|
||||
value!
|
||||
|
||||
# Match control flow operator
|
||||
|
||||
Think of \`switch\`, but for enums.
|
||||
|
||||
``` rust
|
||||
enum Coin {
|
||||
Penny,
|
||||
Nickel,
|
||||
Dime,
|
||||
Quarter,
|
||||
}
|
||||
|
||||
fn value_in_cents(coin: Coin) -> u8 {
|
||||
match coin {
|
||||
Coin::Penny => {
|
||||
println!("Lucky penny!");
|
||||
1
|
||||
}
|
||||
Coin::Nickel => 5,
|
||||
Coin::Dime => 10,
|
||||
Coin::Quarter => 25,
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
|
||||
## Patterns that bind to values
|
||||
|
||||
Another useful feature of match arms is that they can bind to the parts
|
||||
of the values that match the pattern. This is how we can extract values
|
||||
out of enum variants.
|
||||
|
||||
``` rust
|
||||
#[derive(Debug)]
|
||||
enum UsState {
|
||||
Alabama,
|
||||
Alaska,
|
||||
// --snip--
|
||||
}
|
||||
|
||||
enum Coin {
|
||||
Penny,
|
||||
Nickel,
|
||||
Dime,
|
||||
Quarter(UsState),
|
||||
}
|
||||
|
||||
fn value_in_cents(coin: Coin) -> u8 {
|
||||
match coin {
|
||||
Coin::Penny => 1,
|
||||
Coin::Nickel => 5,
|
||||
Coin::Dime => 10,
|
||||
Coin::Quarter(state) => {
|
||||
println!("State quarter from {:?}!", state);
|
||||
25
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
value_in_cents(Coin::Quarter(UsState::Alaska));
|
||||
}
|
||||
```
|
||||
|
||||
## Matching with Option\<T\>
|
||||
|
||||
\`match\` also plays nice with \`Option\<t\>\`:
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
fn plus_one(x: Option<i32>) -> Option<i32> {
|
||||
match x {
|
||||
None => None,
|
||||
Some(i) => Some(i + 1),
|
||||
}
|
||||
}
|
||||
|
||||
let five = Some(5);
|
||||
let six = plus_one(five);
|
||||
let none = plus_one(None);
|
||||
}
|
||||
```
|
||||
|
||||
## The \_ Placeholder
|
||||
|
||||
Rust also has a pattern we can use when we don’t want to list all
|
||||
possible values:
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let some_u8_value = 0u8;
|
||||
match some_u8_value {
|
||||
1 => println!("one"),
|
||||
3 => println!("three"),
|
||||
5 => println!("five"),
|
||||
7 => println!("seven"),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## if let syntax suger
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let some_u8_value = Some(0u8);
|
||||
match some_u8_value {
|
||||
Some(3) => println!("three"),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
is the same as
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let some_u8_value = Some(0u8);
|
||||
if let Some(3) = some_u8_value {
|
||||
println!("three");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
and
|
||||
|
||||
``` rust
|
||||
#[derive(Debug)]
|
||||
enum UsState {
|
||||
Alabama,
|
||||
Alaska,
|
||||
// --snip--
|
||||
}
|
||||
|
||||
enum Coin {
|
||||
Penny,
|
||||
Nickel,
|
||||
Dime,
|
||||
Quarter(UsState),
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let coin = Coin::Penny;
|
||||
let mut count = 0;
|
||||
match coin {
|
||||
Coin::Quarter(state) => println!("State quarter from {:?}!", state),
|
||||
_ => count += 1,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
is the same as
|
||||
|
||||
``` rust
|
||||
#[derive(Debug)]
|
||||
enum UsState {
|
||||
Alabama,
|
||||
Alaska,
|
||||
// --snip--
|
||||
}
|
||||
|
||||
enum Coin {
|
||||
Penny,
|
||||
Nickel,
|
||||
Dime,
|
||||
Quarter(UsState),
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let coin = Coin::Penny;
|
||||
let mut count = 0;
|
||||
if let Coin::Quarter(state) = coin {
|
||||
println!("State quarter from {:?}!", state);
|
||||
} else {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
```
|
38
content/wiki/20200902162305-regular_expressions.md
Normal file
38
content/wiki/20200902162305-regular_expressions.md
Normal file
|
@ -0,0 +1,38 @@
|
|||
---
|
||||
date: 2020-09-02
|
||||
id: 9f63288d-8d70-4b20-a853-66c8f75418c0
|
||||
title: JavaScript Regular Expressions
|
||||
---
|
||||
|
||||
# Prototype Methods
|
||||
|
||||
- [test](20201104101723-javascript_regexp_test_method)
|
||||
- [exec](20201104101924-javascript_regexp_exec_method)
|
||||
- [match](20201104102212-javascript_regexp_match_method)
|
||||
- [matchAll](20201116165324-matchall_expression)
|
||||
- [replace](20201104102343-javascript_regexp_replace_method)
|
||||
- [search](20201104102506-javascript_regexp_search_method)
|
||||
|
||||
# Groups
|
||||
|
||||
- [JavaScript RegExp Numbered Capture
|
||||
Groups](20201104095851-javascript_regexp_numbered_capture_groups)
|
||||
- [JavaScript RegExp Named Capture
|
||||
Groups](20201104100431-javascript_regexp_named_capture_groups)
|
||||
|
||||
# Escapes
|
||||
|
||||
- [JavaScript RegExp Unicode Property
|
||||
Escapes](20201106090634-javascript_regexp_unicode_property_escapes)
|
||||
|
||||
# Assertions
|
||||
|
||||
- [Lookahead
|
||||
Assertions](20201109132457-javascript_lookahead_assertions)
|
||||
- [Lookbehind
|
||||
Assertions](20201109132944-javascript_lookbehind_assertions)
|
||||
|
||||
# Flags
|
||||
|
||||
- [JavaScript RegExp /s flag](20201110094807-javascript_regexp_s_flag)
|
||||
- [JavaScript RegExp /u flag](20201110095139-javascript_regexp_u_flag)
|
57
content/wiki/20200909202454-errors.md
Normal file
57
content/wiki/20200909202454-errors.md
Normal file
|
@ -0,0 +1,57 @@
|
|||
---
|
||||
date: 2020-09-09
|
||||
id: 5114b51a-da22-4c9c-a12c-c416aeb984b6
|
||||
title: Golang Errors
|
||||
---
|
||||
|
||||
# Basics
|
||||
|
||||
Go supports Errors
|
||||
|
||||
``` go
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func ThrowError(throwError bool) error {
|
||||
if throwError {
|
||||
return errors.New("This is an error")
|
||||
}
|
||||
|
||||
fmt.Println("No error was thrown!")
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
ThrowError(true)
|
||||
ThrowError(false)
|
||||
}
|
||||
```
|
||||
|
||||
# Wrappers
|
||||
|
||||
It appears to be good practice to make errors a `const`. This example
|
||||
uses the Error [interface](20200831171822-interfaces):
|
||||
|
||||
``` go
|
||||
const (
|
||||
ErrNotFound = DictionaryErr("could not find the word you were looking for")
|
||||
ErrWordExists = DictionaryErr("cannot add word because it already exists")
|
||||
)
|
||||
|
||||
type DictionaryErr string
|
||||
|
||||
func (e DictionaryErr) Error() string {
|
||||
return string(e)
|
||||
}
|
||||
```
|
||||
|
||||
# Handy Links
|
||||
|
||||
- Constant errors[^1]
|
||||
|
||||
# Footnotes
|
||||
|
||||
[^1]: <https://dave.cheney.net/2016/04/07/constant-errors>
|
27
content/wiki/20200911150451-callbacks.md
Normal file
27
content/wiki/20200911150451-callbacks.md
Normal file
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
date: 2020-09-11
|
||||
id: 6b091d50-aa10-4ba8-a652-43cd5433371e
|
||||
title: JavaScript Callbacks
|
||||
---
|
||||
|
||||
# Examples
|
||||
|
||||
## setTimeout
|
||||
|
||||
``` javascript
|
||||
setTimeout(() => { console.log("This will echo after 2 seconds!"); }, 2000);
|
||||
```
|
||||
|
||||
# ES6
|
||||
|
||||
## Best practices
|
||||
|
||||
### Prefer arrow functions as callbacks
|
||||
|
||||
As callbacks, [arrow functions](20201006111349-arrow_functions) have two
|
||||
advantages over traditional functions:
|
||||
|
||||
- `this` is lexical and therefore safer to use.
|
||||
- Their syntax is more compact. That matters especially in functional
|
||||
programming, where there are many higher-order functions and methods
|
||||
(functions and methods whose parameters are functions).
|
39
content/wiki/20200911154351-promises.md
Normal file
39
content/wiki/20200911154351-promises.md
Normal file
|
@ -0,0 +1,39 @@
|
|||
---
|
||||
date: 2020-09-11
|
||||
id: 14e0ce4b-b4b1-46fe-946a-c519550682ac
|
||||
title: JavaScript Promises
|
||||
---
|
||||
|
||||
# Introduction
|
||||
|
||||
A Promise[^1] is an asynchronous action that may complete at some point
|
||||
and produce a value. It is able to notify anyone who is interested when
|
||||
its value is available.
|
||||
|
||||
``` javascript
|
||||
let fifteen = Promise.resolve(15);
|
||||
fifteen.then(value => console.log(`Got ${value}`))
|
||||
```
|
||||
|
||||
# Parallel
|
||||
|
||||
- [Executing Promises in Parallel
|
||||
(Promises.all)](20201111094957-executing_promises_in_parallel_promises_all)
|
||||
- [Promise.allSettled](20201116163327-promise_allsettled)
|
||||
|
||||
# Errors
|
||||
|
||||
- [Catching Promise Errors](20201111095100-catching_promise_errors)
|
||||
- [Finally](20201111095454-javascript_promises_finally)
|
||||
|
||||
# Producing & Consuming
|
||||
|
||||
Use [Async functions](20201026103714-javascript_async_functions) instead
|
||||
of this.
|
||||
|
||||
- [Producing Promises](20201111095230-producing_promises)
|
||||
- [Consuming Promises](20201111095316-javascript_consuming_promises)
|
||||
|
||||
# Footnotes
|
||||
|
||||
[^1]: <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise>
|
123
content/wiki/20200911155947-generators.md
Normal file
123
content/wiki/20200911155947-generators.md
Normal file
|
@ -0,0 +1,123 @@
|
|||
---
|
||||
date: 2020-09-11
|
||||
id: b2b11ef2-898f-45c7-ad25-967ac7bc9d8b
|
||||
title: JavaScript Generators
|
||||
---
|
||||
|
||||
# ES6
|
||||
|
||||
## Introduction
|
||||
|
||||
Generators are processes that you can pause and resume. Generators are
|
||||
defined with `function*`.
|
||||
|
||||
``` javascript
|
||||
const foo = function* () {
|
||||
yield 'a';
|
||||
yield 'b';
|
||||
yield 'c';
|
||||
};
|
||||
|
||||
let str = '';
|
||||
for (const val of foo()) {
|
||||
str = str + val;
|
||||
}
|
||||
|
||||
console.log(str);
|
||||
```
|
||||
|
||||
## Generator Kinds
|
||||
|
||||
### Generator function declarations
|
||||
|
||||
``` javascript
|
||||
function* genFunc() { }
|
||||
const genObj = genFunc();
|
||||
```
|
||||
|
||||
### Generator function expressions
|
||||
|
||||
``` javascript
|
||||
const genFunc = function* () { };
|
||||
const genObj = genFunc();
|
||||
```
|
||||
|
||||
### Generator method definitions in object literals
|
||||
|
||||
``` javascript
|
||||
const obj = {
|
||||
* generatorMethod() {
|
||||
}
|
||||
};
|
||||
const genObj = obj.generatorMethod();
|
||||
```
|
||||
|
||||
### Generator method definitions in class definitions
|
||||
|
||||
``` javascript
|
||||
class MyClass {
|
||||
* generatorMethod() {
|
||||
}
|
||||
}
|
||||
const myInst = new MyClass();
|
||||
const genObj = myInst.generatorMethod();
|
||||
```
|
||||
|
||||
# Examples
|
||||
|
||||
## Iterables
|
||||
|
||||
``` javascript
|
||||
function* objectEntries(obj) {
|
||||
const propKeys = Reflect.ownKeys(obj);
|
||||
|
||||
for (const propKey of propKeys) {
|
||||
// `yield` returns a value and then pauses
|
||||
// the generator. Later, execution continues
|
||||
// where it was previously paused.
|
||||
yield [propKey, obj[propKey]];
|
||||
}
|
||||
}
|
||||
|
||||
const jane = { first: 'Jane', last: 'Doe' };
|
||||
for (const [key,value] of objectEntries(jane)) {
|
||||
console.log(`${key}: ${value}`);
|
||||
}
|
||||
|
||||
// Output:
|
||||
// first: Jane
|
||||
// last: Doe
|
||||
```
|
||||
|
||||
## Async Iterables
|
||||
|
||||
``` javascript
|
||||
async function* createAsyncIterable(syncIterable) {
|
||||
for (const elem of syncIterable) {
|
||||
yield elem;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Asynchronous code
|
||||
|
||||
``` javascript
|
||||
const fetchJson = co.wrap(function* (url) {
|
||||
try {
|
||||
let request = yield fetch(url);
|
||||
let text = yield request.text();
|
||||
return JSON.parse(text);
|
||||
}
|
||||
catch (error) {
|
||||
console.log(`ERROR: ${error.stack}`);
|
||||
}
|
||||
});
|
||||
|
||||
fetchJson('http://example.com/some_file.json')
|
||||
.then(obj => console.log(obj));
|
||||
```
|
||||
|
||||
# Also see
|
||||
|
||||
- [Iterables](20201014092625-javascript_iterables)
|
||||
- [Promises](20200911154351-promises)
|
148
content/wiki/20200915140449-vectors.md
Normal file
148
content/wiki/20200915140449-vectors.md
Normal file
|
@ -0,0 +1,148 @@
|
|||
---
|
||||
date: 2020-09-15
|
||||
id: 2eec2c96-e006-4a53-b5cc-fd39f466a6b7
|
||||
title: Rust Vectors
|
||||
---
|
||||
|
||||
# Traits
|
||||
|
||||
## std
|
||||
|
||||
### convert
|
||||
|
||||
- [TryInto](20201119171245-tryinto)
|
||||
|
||||
# Description
|
||||
|
||||
Vectors allow you to store more than one value in a single data
|
||||
structure that puts all the values next to each other in memory. Vectors
|
||||
can only store values of the same type. They are useful when you have a
|
||||
list of items, such as the lines of text in a file or the prices of
|
||||
items in a shopping cart.
|
||||
|
||||
# Creating a New Vector
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let v: Vec<i32> = Vec::new();
|
||||
}
|
||||
```
|
||||
|
||||
## vec! macro
|
||||
|
||||
Rust can often infer the type of value you want to store in the Vector.
|
||||
For convenience one can also use the [vec!
|
||||
macro](https://doc.rust-lang.org/std/macro.vec.html).
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let v = vec![1, 2, 3];
|
||||
}
|
||||
```
|
||||
|
||||
# Updating a Vector
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let mut v = Vec::new();
|
||||
|
||||
v.push(5);
|
||||
v.push(6);
|
||||
v.push(7);
|
||||
v.push(8);
|
||||
}
|
||||
```
|
||||
|
||||
# Dropping a Vector
|
||||
|
||||
Like other [structs](20200831193417-structs), vectors are freed when
|
||||
they go out of scope, along with the vector contents:
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
{
|
||||
let v = vec![1, 2, 3, 4];
|
||||
|
||||
// do stuff with v
|
||||
} // <- v goes out of scope and is freed here
|
||||
}
|
||||
```
|
||||
|
||||
# Read Vector elements
|
||||
|
||||
There are two ways to reference a value stored in a vector:
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let v = vec![1, 2, 3, 4, 5];
|
||||
|
||||
let third: &i32 = &v[2];
|
||||
println!("The third element is {}", third);
|
||||
|
||||
match v.get(2) {
|
||||
Some(third) => println!("The third element is {}", third),
|
||||
None => println!("There is no third element."),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Using
|
||||
[get](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.get)
|
||||
together with
|
||||
[match](https://doc.rust-lang.org/rust-by-example/flow_control/match.html)
|
||||
seems preferable, as trying to get non existant elements with method \#1
|
||||
will cause an \`index out of bounds\` panic:
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let v = vec![1, 2, 3, 4, 5];
|
||||
|
||||
let does_not_exist = &v[100];
|
||||
let does_not_exist = v.get(100);
|
||||
}
|
||||
```
|
||||
|
||||
When the `get` method is passed an index that is outside the vector, it
|
||||
returns `None` without panicking.
|
||||
|
||||
# Iteration
|
||||
|
||||
## Immutable references
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let v = vec![100, 32, 57];
|
||||
for i in &v {
|
||||
println!("{}", i);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Mutable references
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let mut v = vec![100, 32, 57];
|
||||
for i in &mut v {
|
||||
*i += 50;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# Using Enums to store multiple types
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
enum SpreadsheetCell {
|
||||
Int(i32),
|
||||
Float(f64),
|
||||
Text(String),
|
||||
}
|
||||
|
||||
let row = vec![
|
||||
SpreadsheetCell::Int(3),
|
||||
SpreadsheetCell::Text(String::from("blue")),
|
||||
SpreadsheetCell::Float(10.12),
|
||||
];
|
||||
}
|
||||
```
|
145
content/wiki/20200915151358-strings.md
Normal file
145
content/wiki/20200915151358-strings.md
Normal file
|
@ -0,0 +1,145 @@
|
|||
---
|
||||
date: 2020-09-15
|
||||
id: 490f0710-971d-4150-a339-4a8c2f5d19a8
|
||||
title: Rust Strings
|
||||
---
|
||||
|
||||
# Description
|
||||
|
||||
The `String` type, which is provided by Rust’s standard library rather
|
||||
than coded into the core language, is a growable, mutable, owned, UTF-8
|
||||
encoded string type. When Rustaceans refer to “strings” in Rust, they
|
||||
usually mean the `String` and the string slice `&str` types, not just
|
||||
one of those types. Although this section is largely about `String`,
|
||||
both types are used heavily in Rust’s standard library, and both
|
||||
`String` and string slices are UTF-8 encoded.
|
||||
|
||||
# Creating a New String
|
||||
|
||||
Many [Vector operations](20200915140449-vectors) are also available for
|
||||
Strings.
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let mut s = String::new();
|
||||
}
|
||||
```
|
||||
|
||||
## to~string~
|
||||
|
||||
To generate a `String` with initial data we can use the
|
||||
[to~string~](https://doc.rust-lang.org/std/string/trait.ToString.html#tymethod.to_string)
|
||||
method:
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let data = "initial contents";
|
||||
|
||||
let s = data.to_string();
|
||||
|
||||
// the method also works on a literal directly:
|
||||
let s = "initial contents".to_string();
|
||||
}
|
||||
```
|
||||
|
||||
## String::from
|
||||
|
||||
The same can be accomplished with `String::from`:
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let s = String::from("initial contents");
|
||||
}
|
||||
```
|
||||
|
||||
# Updating a String
|
||||
|
||||
## push~str~
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let mut s = String::from("foo");
|
||||
s.push_str("bar");
|
||||
|
||||
println!("s is {}", s)
|
||||
}
|
||||
```
|
||||
|
||||
## push
|
||||
|
||||
`push` adds a single character to a string:
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let mut s = String::from("lo");
|
||||
s.push('l');
|
||||
|
||||
println!("s is {}", s)
|
||||
}
|
||||
```
|
||||
|
||||
# Concatentation
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let s1 = String::from("Hello, ");
|
||||
let s2 = String::from("world!");
|
||||
let s3 = s1 + &s2; // note s1 has been moved here and can no longer be used
|
||||
|
||||
println!("s3 is {}", s3)
|
||||
}
|
||||
```
|
||||
|
||||
## Concatenate multiple strings
|
||||
|
||||
### With +
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let s1 = String::from("tic");
|
||||
let s2 = String::from("tac");
|
||||
let s3 = String::from("toe");
|
||||
|
||||
let s = s1 + "-" + &s2 + "-" + &s3;
|
||||
|
||||
println!("s is {}", s)
|
||||
}
|
||||
```
|
||||
|
||||
### With format!
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let s1 = String::from("tic");
|
||||
let s2 = String::from("tac");
|
||||
let s3 = String::from("toe");
|
||||
|
||||
let s = format!("{}-{}-{}", s1, s2, s3);
|
||||
|
||||
println!("s is {}", s)
|
||||
}
|
||||
```
|
||||
|
||||
# Iteration
|
||||
|
||||
## Chars
|
||||
|
||||
``` rust
|
||||
#![allow(unused)]
|
||||
fn main() {
|
||||
for c in "नमस्ते".chars() {
|
||||
println!("{}", c);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Bytes
|
||||
|
||||
``` rust
|
||||
#![allow(unused)]
|
||||
fn main() {
|
||||
for b in "नमस्ते".bytes() {
|
||||
println!("{}", b);
|
||||
}
|
||||
}
|
||||
```
|
137
content/wiki/20200915153033-hash_maps.md
Normal file
137
content/wiki/20200915153033-hash_maps.md
Normal file
|
@ -0,0 +1,137 @@
|
|||
---
|
||||
date: 2020-09-15
|
||||
id: 2b38c21d-4971-42fb-9b87-5d68468e95e0
|
||||
title: Rust Hash Maps
|
||||
---
|
||||
|
||||
# Description
|
||||
|
||||
The type `HashMap<K, V>` stores a mapping of keys of type `K` to values
|
||||
of type `V`. It does this via a hashing function, which determines how
|
||||
it places these keys and values into memory. Many programming languages
|
||||
support this kind of data structure, but they often use a different
|
||||
name, such as hash, map, object, hash table, dictionary, or associative
|
||||
array, just to name a few.
|
||||
|
||||
## Creating a New Hash Maps
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
use std::collections::HashMap;
|
||||
|
||||
let mut scores = HashMap::new();
|
||||
|
||||
scores.insert(String::from("Blue"), 10);
|
||||
scores.insert(String::from("Yellow"), 50);
|
||||
|
||||
println!("{}", scores["Blue"])
|
||||
}
|
||||
```
|
||||
|
||||
### collect
|
||||
|
||||
Another way of constructing a hash map is by using iterators and the
|
||||
[collect](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.collect)
|
||||
method on a vector of tuples, where each tuple consists of a key and its
|
||||
value.
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
use std::collections::HashMap;
|
||||
|
||||
let teams = vec![String::from("Blue"), String::from("Yellow")];
|
||||
let initial_scores = vec![10, 50];
|
||||
|
||||
let scores: HashMap<_, _> = teams.into_iter().zip(initial_scores.into_iter()).collect();
|
||||
|
||||
println!("{}", scores["Blue"])
|
||||
}
|
||||
```
|
||||
|
||||
## Ownership
|
||||
|
||||
For types that implement the `Copy` trait, like `i32`, the values are
|
||||
copied into the hash map. For owned values like `String`, the values
|
||||
will be moved and the hash map will be the owner of those values:
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
use std::collections::HashMap;
|
||||
|
||||
let field_name = String::from("Favorite color");
|
||||
let field_value = String::from("Blue");
|
||||
|
||||
let mut map = HashMap::new();
|
||||
map.insert(field_name, field_value);
|
||||
// field_name and field_value are invalid at this point
|
||||
}
|
||||
```
|
||||
|
||||
## Accessing values
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
use std::collections::HashMap;
|
||||
|
||||
let mut scores = HashMap::new();
|
||||
|
||||
scores.insert(String::from("Blue"), 10);
|
||||
scores.insert(String::from("Yellow"), 50);
|
||||
|
||||
for (key, value) in &scores {
|
||||
println!("{}: {}", key, value);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Updating
|
||||
|
||||
### Overwriting a Value
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
use std::collections::HashMap;
|
||||
|
||||
let mut scores = HashMap::new();
|
||||
|
||||
scores.insert(String::from("Blue"), 10);
|
||||
scores.insert(String::from("Blue"), 25);
|
||||
|
||||
println!("{:?}", scores);
|
||||
}
|
||||
```
|
||||
|
||||
### Inserting a value only if the Key has no value
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
use std::collections::HashMap;
|
||||
|
||||
let mut scores = HashMap::new();
|
||||
scores.insert(String::from("Blue"), 10);
|
||||
|
||||
scores.entry(String::from("Yellow")).or_insert(50);
|
||||
scores.entry(String::from("Blue")).or_insert(50);
|
||||
|
||||
println!("{:?}", scores);
|
||||
}
|
||||
```
|
||||
|
||||
### Updating a value based on the old value
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
use std::collections::HashMap;
|
||||
|
||||
let text = "hello world wonderful world";
|
||||
|
||||
let mut map = HashMap::new();
|
||||
|
||||
for word in text.split_whitespace() {
|
||||
let count = map.entry(word).or_insert(0);
|
||||
*count += 1;
|
||||
}
|
||||
|
||||
println!("{:?}", map);
|
||||
}
|
||||
```
|
34
content/wiki/20200916162727-unrecoverable_errors.md
Normal file
34
content/wiki/20200916162727-unrecoverable_errors.md
Normal file
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
date: 2020-09-16
|
||||
id: 2a1d0b2f-9f23-4872-a83f-aa01a84756b5
|
||||
title: Rust Unrecoverable Errors
|
||||
---
|
||||
|
||||
# Unwinding vs Aborting
|
||||
|
||||
By default, when a panic occurs, the program starts *unwinding*, which
|
||||
means Rust walks back up the stack and cleans up the data from each
|
||||
function it encounters. But this walking back and cleanup is a lot of
|
||||
work. The alternative is to immediately abort, which ends the program
|
||||
without cleaning up. Memory that the program was using will then need to
|
||||
be cleaned up by the operating system. If in your project you need to
|
||||
make the resulting binary as small as possible, you can switch from
|
||||
unwinding to aborting upon a panic by adding `panic = 'abort'` to the
|
||||
appropriate `[profile]` sections in your *Cargo.toml* file. For example,
|
||||
if you want to abort on panic in release mode, add this:
|
||||
|
||||
``` toml
|
||||
[profile.release]
|
||||
panic = 'abort'
|
||||
```
|
||||
|
||||
# panic!
|
||||
|
||||
When doodie hits the fan and there's no way out, use the
|
||||
[panic!](https://doc.rust-lang.org/std/macro.panic.html) macro:
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
panic!("crash and burn");
|
||||
}
|
||||
```
|
171
content/wiki/20200916163737-recoverable_errors.md
Normal file
171
content/wiki/20200916163737-recoverable_errors.md
Normal file
|
@ -0,0 +1,171 @@
|
|||
---
|
||||
date: 2020-09-16
|
||||
id: cbdaa6b4-cf72-45fb-ac16-79afd8900478
|
||||
title: Rust Recoverable Errors
|
||||
---
|
||||
|
||||
# match
|
||||
|
||||
In Rust we use the [match](20201006102934-pattern_syntax) expression to
|
||||
check for errors in the
|
||||
[Result](https://doc.rust-lang.org/std/result/enum.Result.html):
|
||||
|
||||
``` rust
|
||||
use std::fs::File;
|
||||
|
||||
fn main() {
|
||||
let f = File::open("hello.txt");
|
||||
|
||||
let f = match f {
|
||||
Ok(file) => file,
|
||||
Err(error) => panic!("Problem opening the file: {:?}", error),
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Generally speaking you want to perform different actions depending on
|
||||
the error type:
|
||||
|
||||
``` rust
|
||||
use std::fs::File;
|
||||
use std::io::ErrorKind;
|
||||
|
||||
fn main() {
|
||||
let f = File::open("hello.txt");
|
||||
|
||||
let f = match f {
|
||||
Ok(file) => file,
|
||||
Err(error) => match error.kind() {
|
||||
ErrorKind::NotFound => match File::create("hello.txt") {
|
||||
Ok(fc) => fc,
|
||||
Err(e) => panic!("Problem creating the file: {:?}", e),
|
||||
},
|
||||
other_error => panic!("Problem opening the file: {:?}", other_error),
|
||||
},
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Ditching match altogether
|
||||
|
||||
A more elegant way of writing the above:
|
||||
|
||||
``` rust
|
||||
use std::fs::File;
|
||||
use std::io::ErrorKind;
|
||||
|
||||
fn main() {
|
||||
let f = File::open("hello.txt").unwrap_or_else(|error| {
|
||||
if error.kind() == ErrorKind::NotFound {
|
||||
File::create("hello.txt").unwrap_or_else(|error| {
|
||||
panic!("Problem creating the file: {:?}", error);
|
||||
})
|
||||
} else {
|
||||
panic!("Problem opening the file: {:?}", error);
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
# Panic on Error shortcuts
|
||||
|
||||
## unwrap
|
||||
|
||||
If the `Result` value is `Ok`,
|
||||
[unwrap](https://doc.rust-lang.org/std/option/enum.Option.html#method.unwrap)
|
||||
will return the value inside the `Ok`. If the `Result` is of the `Err`
|
||||
variant, unwrap will call the `panic!` macro
|
||||
|
||||
``` rust
|
||||
use std::fs::File;
|
||||
|
||||
fn main() {
|
||||
let f = File::open("hello.txt").unwrap();
|
||||
}
|
||||
```
|
||||
|
||||
## expect
|
||||
|
||||
[expect](https://doc.rust-lang.org/std/option/enum.Option.html#method.expect)
|
||||
is almost the same as unwrap, the only difference being that it allws us
|
||||
to choose the panic! error message:
|
||||
|
||||
``` rust
|
||||
use std::fs::File;
|
||||
|
||||
fn main() {
|
||||
let f = File::open("hello.txt").expect("Failed to open hello.txt");
|
||||
}
|
||||
```
|
||||
|
||||
# Propagating Errors
|
||||
|
||||
When you’re writing a function whose implementation calls something that
|
||||
might fail, instead of handling the error within this function, you can
|
||||
return the error to the calling code so that it can decide what to do.
|
||||
This is known as propagating the error and gives more control to the
|
||||
calling code, where there might be more information or logic that
|
||||
dictates how the error should be handled than what you have available in
|
||||
the context of your code.
|
||||
|
||||
``` rust
|
||||
#![allow(unused)]
|
||||
fn main() {
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::Read;
|
||||
|
||||
fn read_username_from_file() -> Result<String, io::Error> {
|
||||
let f = File::open("hello.txt");
|
||||
|
||||
let mut f = match f {
|
||||
Ok(file) => file,
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
|
||||
let mut s = String::new();
|
||||
|
||||
match f.read_to_string(&mut s) {
|
||||
Ok(_) => Ok(s),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This can of course be refactored to something nicer:
|
||||
|
||||
``` rust
|
||||
#![allow(unused)]
|
||||
fn main() {
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::Read;
|
||||
|
||||
fn read_username_from_file() -> Result<String, io::Error> {
|
||||
let mut f = File::open("hello.txt")?;
|
||||
let mut s = String::new();
|
||||
f.read_to_string(&mut s)?;
|
||||
Ok(s)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
And this can be refactored even more:
|
||||
|
||||
``` rust
|
||||
#![allow(unused)]
|
||||
fn main() {
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::Read;
|
||||
|
||||
fn read_username_from_file() -> Result<String, io::Error> {
|
||||
let mut s = String::new();
|
||||
|
||||
File::open("hello.txt")?.read_to_string(&mut s)?;
|
||||
|
||||
Ok(s)
|
||||
}
|
||||
}
|
||||
```
|
31
content/wiki/20200916172802-commonjs.md
Normal file
31
content/wiki/20200916172802-commonjs.md
Normal file
|
@ -0,0 +1,31 @@
|
|||
---
|
||||
date: 2020-09-16
|
||||
id: f41437f1-359e-41c9-894b-e5785c29d729
|
||||
title: CommonJS
|
||||
---
|
||||
|
||||
# Syntax
|
||||
|
||||
``` javascript
|
||||
const ordinal = require("ordinal");
|
||||
const {days, months} = require("date-names");
|
||||
|
||||
exports.formatDate = function(date, format) {
|
||||
return format.replace(/YYYY|M(MMM)?|Do?|dddd/g, tag => {
|
||||
if (tag == "YYYY") return date.getFullYear();
|
||||
if (tag == "M") return date.getMonth();
|
||||
if (tag == "MMMM") return months[date.getMonth()];
|
||||
if (tag == "D") return date.getDate();
|
||||
if (tag == "Do") return ordinal(date.getDate());
|
||||
if (tag == "dddd") return days[date.getDay()];
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
``` javascript
|
||||
const {formatDate} = require("./format-date");
|
||||
|
||||
console.log(formatDate(new Date(2017, 9, 13),
|
||||
"dddd the Do"));
|
||||
// → Friday the 13th
|
||||
```
|
20
content/wiki/20200916172914-ecmascript.md
Normal file
20
content/wiki/20200916172914-ecmascript.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
date: 2020-09-16
|
||||
id: 7fa2a1e8-deae-47f9-83ee-e4f4f84eec16
|
||||
title: ECMAScript Modules
|
||||
---
|
||||
|
||||
# Syntax
|
||||
|
||||
``` javascript
|
||||
import ordinal from "ordinal";
|
||||
import {days, months} from "date-names";
|
||||
|
||||
export function formatDate(date, format) { /* ... */ }
|
||||
```
|
||||
|
||||
## Default export
|
||||
|
||||
``` javascript
|
||||
export default ["Winter", "Spring", "Summer", "Autumn"];
|
||||
```
|
9
content/wiki/20200917155644-reflection.md
Normal file
9
content/wiki/20200917155644-reflection.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
date: 2020-09-17
|
||||
id: 8fdb1d27-7983-4ab0-bda3-120715000797
|
||||
title: Reflection
|
||||
---
|
||||
|
||||
# Everything you need to know about Reflection
|
||||
|
||||
Avoid at all costs!
|
135
content/wiki/20200917161757-generics.md
Normal file
135
content/wiki/20200917161757-generics.md
Normal file
|
@ -0,0 +1,135 @@
|
|||
---
|
||||
date: 2020-09-17
|
||||
id: 9062c9c0-b2d5-4719-b15b-6fe5122b6a9e
|
||||
title: Rust Generics
|
||||
---
|
||||
|
||||
# Function definitions
|
||||
|
||||
We read the following definition as: the function largest is generic
|
||||
over some type T. This function has one parameter named list, which is a
|
||||
slice of values of type T. The largest function will return a reference
|
||||
to a value of the same type T.
|
||||
|
||||
``` rust
|
||||
fn largest<T>(list: &[T]) -> &T {
|
||||
let mut largest = list[0];
|
||||
|
||||
for item in list {
|
||||
if item > largest {
|
||||
largest = item;
|
||||
}
|
||||
}
|
||||
|
||||
largest
|
||||
}
|
||||
```
|
||||
|
||||
# Struct definitions
|
||||
|
||||
``` rust
|
||||
struct Point<T> {
|
||||
x: T,
|
||||
y: T,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let integer = Point { x: 5, y: 10 };
|
||||
let float = Point { x: 1.0, y: 4.0 };
|
||||
}
|
||||
```
|
||||
|
||||
A struct can also have multiple generic types:
|
||||
|
||||
``` rust
|
||||
struct Point<T, U> {
|
||||
x: T,
|
||||
y: U,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let both_integer = Point { x: 5, y: 10 };
|
||||
let both_float = Point { x: 1.0, y: 4.0 };
|
||||
let integer_and_float = Point { x: 5, y: 4.0 };
|
||||
}
|
||||
```
|
||||
|
||||
# Enum Definitions
|
||||
|
||||
``` rust
|
||||
#![allow(unused)]
|
||||
fn main() {
|
||||
enum Option<T> {
|
||||
Some(T),
|
||||
None,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
And again with multiple generics:
|
||||
|
||||
``` rust
|
||||
#![allow(unused)]
|
||||
fn main() {
|
||||
enum Result<T, E> {
|
||||
Ok(T),
|
||||
Err(E),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# Method Definitions
|
||||
|
||||
``` rust
|
||||
struct Point<T> {
|
||||
x: T,
|
||||
y: T,
|
||||
}
|
||||
|
||||
impl<T> Point<T> {
|
||||
fn x(&self) -> &T {
|
||||
&self.x
|
||||
}
|
||||
fn y(&self) -> &T {
|
||||
&self.y
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let p = Point { x: 5, y: 10 };
|
||||
|
||||
println!("p.x = {} and p.y={}", p.x(), p.y());
|
||||
}
|
||||
```
|
||||
|
||||
And again with multiple generics:
|
||||
|
||||
``` rust
|
||||
struct Point<T, U> {
|
||||
x: T,
|
||||
y: U,
|
||||
}
|
||||
|
||||
impl<T, U> Point<T, U> {
|
||||
fn mixup<V, W>(self, other: Point<V, W>) -> Point<T, W> {
|
||||
Point {
|
||||
x: self.x,
|
||||
y: other.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let p1 = Point { x: 5, y: 10.4 };
|
||||
let p2 = Point { x: "Hello", y: 'c' };
|
||||
|
||||
let p3 = p1.mixup(p2);
|
||||
|
||||
println!("p3.x = {}, p3.y = {}", p3.x, p3.y);
|
||||
}
|
||||
```
|
||||
|
||||
# Performance of Code Using Generics
|
||||
|
||||
The Rust compiler is very very clever and using generics has no
|
||||
performance penalty
|
198
content/wiki/20200917163203-traits.md
Normal file
198
content/wiki/20200917163203-traits.md
Normal file
|
@ -0,0 +1,198 @@
|
|||
---
|
||||
date: 2020-09-17
|
||||
id: 84046151-f6e2-4051-a4c5-0c82834eaa41
|
||||
title: Rust Traits Syntax
|
||||
---
|
||||
|
||||
# Definition
|
||||
|
||||
``` rust
|
||||
#![allow(unused)]
|
||||
fn main() {
|
||||
pub trait Summary {
|
||||
fn summarize(&self) -> String;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# Implementation
|
||||
|
||||
``` rust
|
||||
#![allow(unused)]
|
||||
fn main() {
|
||||
pub trait Summary {
|
||||
fn summarize(&self) -> String;
|
||||
}
|
||||
|
||||
pub struct NewsArticle {
|
||||
pub headline: String,
|
||||
pub location: String,
|
||||
pub author: String,
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
impl Summary for NewsArticle {
|
||||
fn summarize(&self) -> String {
|
||||
format!("{}, by {} ({})", self.headline, self.author, self.location)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Tweet {
|
||||
pub username: String,
|
||||
pub content: String,
|
||||
pub reply: bool,
|
||||
pub retweet: bool,
|
||||
}
|
||||
|
||||
impl Summary for Tweet {
|
||||
fn summarize(&self) -> String {
|
||||
format!("{}: {}", self.username, self.content)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Default Implementations
|
||||
|
||||
``` rust
|
||||
#![allow(unused)]
|
||||
fn main() {
|
||||
pub trait Summary {
|
||||
fn summarize(&self) -> String {
|
||||
String::from("(Read more...)")
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NewsArticle {
|
||||
pub headline: String,
|
||||
pub location: String,
|
||||
pub author: String,
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
impl Summary for NewsArticle {}
|
||||
|
||||
pub struct Tweet {
|
||||
pub username: String,
|
||||
pub content: String,
|
||||
pub reply: bool,
|
||||
pub retweet: bool,
|
||||
}
|
||||
|
||||
impl Summary for Tweet {
|
||||
fn summarize(&self) -> String {
|
||||
format!("{}: {}", self.username, self.content)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# Traits as Parameters
|
||||
|
||||
``` rust
|
||||
pub trait Summary {
|
||||
fn summarize(&self) -> String;
|
||||
}
|
||||
|
||||
pub struct NewsArticle {
|
||||
pub headline: String,
|
||||
pub location: String,
|
||||
pub author: String,
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
impl Summary for NewsArticle {
|
||||
fn summarize(&self) -> String {
|
||||
format!("{}, by {} ({})", self.headline, self.author, self.location)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Tweet {
|
||||
pub username: String,
|
||||
pub content: String,
|
||||
pub reply: bool,
|
||||
pub retweet: bool,
|
||||
}
|
||||
|
||||
impl Summary for Tweet {
|
||||
fn summarize(&self) -> String {
|
||||
format!("{}: {}", self.username, self.content)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn notify(item: &impl Summary) {
|
||||
println!("Breaking news! {}", item.summarize());
|
||||
}
|
||||
```
|
||||
|
||||
## Specifying Multiple Trait Bounds
|
||||
|
||||
``` rust
|
||||
pub fn notify(item: &(impl Summary + Display)) {
|
||||
```
|
||||
|
||||
This also works on generic types:
|
||||
|
||||
``` rust
|
||||
pub fn notify<T: Summary + Display>(item: &T) {
|
||||
```
|
||||
|
||||
### Clearer Trait Bounds
|
||||
|
||||
``` rust
|
||||
fn some_function<T: Display + Clone, U: Clone + Debug>(t: &T, u: &U) -> i32 {
|
||||
```
|
||||
|
||||
is the same as
|
||||
|
||||
``` rust
|
||||
fn some_function<T, U>(t: &T, u: &U) -> i32
|
||||
where T: Display + Clone,
|
||||
U: Clone + Debug
|
||||
{
|
||||
```
|
||||
|
||||
# Return Types that Implement Traits
|
||||
|
||||
``` rust
|
||||
pub trait Summary {
|
||||
fn summarize(&self) -> String;
|
||||
}
|
||||
|
||||
pub struct NewsArticle {
|
||||
pub headline: String,
|
||||
pub location: String,
|
||||
pub author: String,
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
impl Summary for NewsArticle {
|
||||
fn summarize(&self) -> String {
|
||||
format!("{}, by {} ({})", self.headline, self.author, self.location)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Tweet {
|
||||
pub username: String,
|
||||
pub content: String,
|
||||
pub reply: bool,
|
||||
pub retweet: bool,
|
||||
}
|
||||
|
||||
impl Summary for Tweet {
|
||||
fn summarize(&self) -> String {
|
||||
format!("{}: {}", self.username, self.content)
|
||||
}
|
||||
}
|
||||
|
||||
fn returns_summarizable() -> impl Summary {
|
||||
Tweet {
|
||||
username: String::from("horse_ebooks"),
|
||||
content: String::from(
|
||||
"of course, as you probably already know, people",
|
||||
),
|
||||
reply: false,
|
||||
retweet: false,
|
||||
}
|
||||
}
|
||||
```
|
37
content/wiki/20200918173820-mutex.md
Normal file
37
content/wiki/20200918173820-mutex.md
Normal file
|
@ -0,0 +1,37 @@
|
|||
---
|
||||
date: 2020-09-18
|
||||
id: 56a802e2-3871-4746-aec4-fa4bdae4d4fd
|
||||
title: Golang Mutex
|
||||
---
|
||||
|
||||
# Description
|
||||
|
||||
[Mutex](https://golang.org/pkg/sync/#Mutex) allows up to add locks to
|
||||
our data so it can be accessed safely in a concurrent manner. While
|
||||
locked other threads can't access the data. `Mutexes` should generally
|
||||
be used for [managing
|
||||
state](https://github.com/golang/go/wiki/MutexOrChannel).
|
||||
|
||||
# Syntax
|
||||
|
||||
``` go
|
||||
type Counter struct {
|
||||
mu sync.Mutex
|
||||
value int
|
||||
}
|
||||
|
||||
func (c *Counter) Inc() {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
c.value++
|
||||
}
|
||||
|
||||
func (c *Counter) Value() int {
|
||||
return c.value
|
||||
}
|
||||
|
||||
func NewCounter() *Counter {
|
||||
return &Counter{}
|
||||
}
|
||||
```
|
54
content/wiki/20200918174548-waitgroup.md
Normal file
54
content/wiki/20200918174548-waitgroup.md
Normal file
|
@ -0,0 +1,54 @@
|
|||
---
|
||||
date: 2020-09-18
|
||||
id: 53c0ad13-0c19-4a84-9c67-cc31d036be4d
|
||||
title: Golang WaitGroup
|
||||
---
|
||||
|
||||
# Description
|
||||
|
||||
A [WaitGroup](https://golang.org/pkg/sync/#WaitGroup) waits for a
|
||||
collection of goroutines to finish. The main goroutine calls Add to set
|
||||
the number of goroutines to wait for. Then each of the goroutines runs
|
||||
and calls Done when finished. At the same time, Wait can be used to
|
||||
block until all goroutines have finished.
|
||||
|
||||
A WaitGroup must not be copied after first use.
|
||||
|
||||
# Syntax
|
||||
|
||||
``` go
|
||||
type Counter struct {
|
||||
mu sync.Mutex
|
||||
value int
|
||||
}
|
||||
|
||||
func (c *Counter) Inc() {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
c.value++
|
||||
}
|
||||
|
||||
func (c *Counter) Value() int {
|
||||
return c.value
|
||||
}
|
||||
|
||||
func NewCounter() *Counter {
|
||||
return &Counter{}
|
||||
}
|
||||
|
||||
wantedCount := 1000
|
||||
counter := NewCounter()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(wantedCount)
|
||||
|
||||
for i := 0; i < wantedCount; i++ {
|
||||
go func(w *sync.WaitGroup) {
|
||||
counter.Inc()
|
||||
w.Done()
|
||||
}(&wg)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
```
|
15
content/wiki/20200918180634-rustc.md
Normal file
15
content/wiki/20200918180634-rustc.md
Normal file
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
date: 2020-09-18
|
||||
id: 9089aff1-703d-4628-971a-5f655f7bf09f
|
||||
title: Rustc
|
||||
---
|
||||
|
||||
# Description
|
||||
|
||||
Rustc handles Rust compilation
|
||||
|
||||
# Syntax
|
||||
|
||||
``` shell
|
||||
rustc main.rs
|
||||
```
|
151
content/wiki/20200918180750-cargo.md
Normal file
151
content/wiki/20200918180750-cargo.md
Normal file
|
@ -0,0 +1,151 @@
|
|||
---
|
||||
date: 2020-09-18
|
||||
id: c409c0cd-5284-4333-ae99-bc351ff8ba0d
|
||||
title: Cargo
|
||||
---
|
||||
|
||||
# Description
|
||||
|
||||
Cargo is Rust's build system and package manager.
|
||||
|
||||
# Configuration
|
||||
|
||||
- [Cargo.toml](20201120094652-cargo_toml)
|
||||
|
||||
# Commands
|
||||
|
||||
## Create project
|
||||
|
||||
``` shell
|
||||
cargo new hello_cargo
|
||||
```
|
||||
|
||||
## Build & run project
|
||||
|
||||
``` shell
|
||||
cargo run
|
||||
```
|
||||
|
||||
### Backtrace
|
||||
|
||||
When you want to see an error backtrace set the `RUST_BACKTRACE`
|
||||
environment variable:
|
||||
|
||||
``` shell
|
||||
RUST_BACKTRACE=1 cargo run
|
||||
```
|
||||
|
||||
## Publish to Crates.io
|
||||
|
||||
``` shell
|
||||
cargo publish
|
||||
```
|
||||
|
||||
## Install package
|
||||
|
||||
``` shell
|
||||
cargo install ripgrep
|
||||
```
|
||||
|
||||
## Linting & testing
|
||||
|
||||
Check code
|
||||
|
||||
``` shell
|
||||
cargo check
|
||||
```
|
||||
|
||||
Testing
|
||||
|
||||
``` shell
|
||||
cargo test
|
||||
```
|
||||
|
||||
1. Backtrace
|
||||
|
||||
To backtrace set the `RUST_BACKTRACE` environment variable:
|
||||
|
||||
``` shell
|
||||
RUST_BACKTRACE=1 cargo run
|
||||
```
|
||||
|
||||
2. Threads
|
||||
|
||||
By default cargo runs test in parallel. For more control over this
|
||||
you can pass the number of threads you want to use. For example to
|
||||
only use 1 thread:
|
||||
|
||||
``` shell
|
||||
cargo test -- --test=threads=1
|
||||
```
|
||||
|
||||
3. Show output for passing tests as well as failed tests
|
||||
|
||||
``` shell
|
||||
cargo test -- --show-output
|
||||
```
|
||||
|
||||
4. Pass test name to cargo (this equals test function name)
|
||||
|
||||
``` shell
|
||||
cargo test one_hundred
|
||||
```
|
||||
|
||||
5. Run ignored tests
|
||||
|
||||
``` shell
|
||||
cargo test -- --ignored
|
||||
```
|
||||
|
||||
Fix
|
||||
|
||||
The rustfix tool is included with Rust installations and can
|
||||
automatically fix some compiler warnings.
|
||||
|
||||
``` shell
|
||||
cargo fix
|
||||
```
|
||||
|
||||
## Builds
|
||||
|
||||
### Profiles
|
||||
|
||||
In Rust, release profiles are predefined and customizable profiles with
|
||||
different configurations that allow a programmer to have more control
|
||||
over various options for compiling code. Each profile is configured
|
||||
independently of the others.
|
||||
|
||||
Cargo has two main profiles: the `dev` profile Cargo uses when you run
|
||||
cargo build and the release profile Cargo uses when you run
|
||||
`cargo build --release`. The `dev` profile is defined with good defaults
|
||||
for development, and the `release` profile has good defaults for release
|
||||
builds.
|
||||
|
||||
1. dev
|
||||
|
||||
``` shell
|
||||
cargo build
|
||||
```
|
||||
|
||||
2. build
|
||||
|
||||
``` shell
|
||||
cargo build --release
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
See [Rust Comments](20200827190035-rust_comments) for documentation
|
||||
syntax.
|
||||
|
||||
### Generation
|
||||
|
||||
``` shell
|
||||
cargo doc
|
||||
```
|
||||
|
||||
### Open in browser
|
||||
|
||||
``` shell
|
||||
cargo doc --open
|
||||
```
|
179
content/wiki/20200918183524-tests.md
Normal file
179
content/wiki/20200918183524-tests.md
Normal file
|
@ -0,0 +1,179 @@
|
|||
---
|
||||
date: 2020-09-18
|
||||
id: 23e290f6-c964-4aee-a133-232291ecdba8
|
||||
title: Tests in Rust
|
||||
---
|
||||
|
||||
# Assertions
|
||||
|
||||
## assert!
|
||||
|
||||
``` rust
|
||||
struct Rectangle {
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
impl Rectangle {
|
||||
pub fn can_hold(&self, other: &Rectangle) -> bool {
|
||||
self.width > other.width && self.height > other.height
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Guess {
|
||||
value: i32,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn larger_can_hold_smaller() {
|
||||
let larger = Rectangle {
|
||||
width: 8,
|
||||
height: 7,
|
||||
};
|
||||
let smaller = Rectangle {
|
||||
width: 5,
|
||||
height: 1,
|
||||
};
|
||||
|
||||
assert!(larger.can_hold(&smaller))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn smaller_cannot_hold_larger() {
|
||||
let larger = Rectangle {
|
||||
width: 8,
|
||||
height: 7,
|
||||
};
|
||||
let smaller = Rectangle {
|
||||
width: 5,
|
||||
height: 1,
|
||||
};
|
||||
|
||||
assert!(!smaller.can_hold(&larger))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## assert~eq~!
|
||||
|
||||
``` rust
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(2 + 2, 4);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# Results
|
||||
|
||||
## Contains
|
||||
|
||||
``` rust
|
||||
pub fn greeting(name: &str) -> String {
|
||||
format!("Hello {}!", name)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn greeting_contains_name() {
|
||||
let result = greeting("Carrol");
|
||||
assert!(
|
||||
result.contains("Carrol"),
|
||||
"Greeting did not countain name, value was `{}`",
|
||||
result
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# Annotations
|
||||
|
||||
## should~panic~
|
||||
|
||||
``` rust
|
||||
pub struct Guess {
|
||||
value: i32,
|
||||
}
|
||||
|
||||
impl Guess {
|
||||
pub fn new(value: i32) -> Guess {
|
||||
if value < 1 {
|
||||
panic!(
|
||||
"Guess value must be greater than or equal to 1, got {}.",
|
||||
value
|
||||
);
|
||||
} else if value > 100 {
|
||||
panic!(
|
||||
"Guess value must be less than or equal to 100, got {}.",
|
||||
value
|
||||
);
|
||||
}
|
||||
|
||||
Guess { value }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "Guess value must be less than or equal to 100")]
|
||||
fn greater_than_100() {
|
||||
Guess::new(200);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## ignore
|
||||
|
||||
This ignores tests unless specifically requested:
|
||||
|
||||
``` rust
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn expensive_test() {
|
||||
// code that takes an hour to run
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
|
||||
# Integreation Tests
|
||||
|
||||
Integration tests are their own thing and I'm too lazy to take notes now
|
||||
as it's 18:59 on a Friday. See relevant chapter in [the
|
||||
book](https://doc.rust-lang.org/stable/book/ch11-03-test-organization.html)
|
||||
for more information.
|
||||
|
||||
# Using Result \<T, E\> in Tests
|
||||
|
||||
This is possible for when you want to use the [question mark
|
||||
operator](https://doc.rust-lang.org/edition-guide/rust-2018/error-handling-and-panics/the-question-mark-operator-for-easier-error-handling.html)
|
||||
in your tests:
|
||||
|
||||
``` rust
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_works() -> Result<(), String> {
|
||||
if 2 + 2 == 4 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(String::from("two plus two does not equal four"))
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
70
content/wiki/20200921154246-context.md
Normal file
70
content/wiki/20200921154246-context.md
Normal file
|
@ -0,0 +1,70 @@
|
|||
---
|
||||
date: 2020-09-21
|
||||
id: ad20518c-1a42-4d02-8746-f42be6a46944
|
||||
title: Golang Context
|
||||
---
|
||||
|
||||
# Overview
|
||||
|
||||
Package context defines the Context type, which carries deadlines,
|
||||
cancellation signals, and other request-scoped values across API
|
||||
boundaries and between processes.
|
||||
|
||||
Incoming requests to a server should create a Context, and outgoing
|
||||
calls to servers should accept a Context. The chain of function calls
|
||||
between them must propagate the Context, optionally replacing it with a
|
||||
derived Context created using WithCancel, WithDeadline, WithTimeout, or
|
||||
WithValue. When a Context is canceled, all Contexts derived from it are
|
||||
also canceled.
|
||||
|
||||
The WithCancel, WithDeadline, and WithTimeout functions take a Context
|
||||
(the parent) and return a derived Context (the child) and a CancelFunc.
|
||||
Calling the CancelFunc cancels the child and its children, removes the
|
||||
parent's reference to the child, and stops any associated timers.
|
||||
Failing to call the CancelFunc leaks the child and its children until
|
||||
the parent is canceled or the timer fires. The go vet tool checks that
|
||||
CancelFuncs are used on all control-flow paths.
|
||||
|
||||
Programs that use Contexts should follow these rules to keep interfaces
|
||||
consistent across packages and enable static analysis tools to check
|
||||
context propagation:
|
||||
|
||||
Do not store Contexts inside a struct type; instead, pass a Context
|
||||
explicitly to each function that needs it. The Context should be the
|
||||
first parameter, typically named ctx:
|
||||
|
||||
``` go
|
||||
func DoSomething(ctx context.Context, arg Arg) error {
|
||||
// ... use ctx ...
|
||||
}
|
||||
```
|
||||
|
||||
Do not pass a nil Context, even if a function permits it. Pass
|
||||
context.TODO if you are unsure about which Context to use.
|
||||
|
||||
Use context Values only for request-scoped data that transits processes
|
||||
and APIs, not for passing optional parameters to functions.
|
||||
|
||||
The same Context may be passed to functions running in different
|
||||
goroutines; Contexts are safe for simultaneous use by multiple
|
||||
goroutines.
|
||||
|
||||
See <https://blog.golang.org/context> for example code for a server that
|
||||
uses Contexts.
|
||||
|
||||
# Googles take
|
||||
|
||||
> At Google, we require that Go programmers pass a Context parameter as
|
||||
> the first argument to every function on the call path between incoming
|
||||
> and outgoing requests. This allows Go code developed by many different
|
||||
> teams to interoperate well. It provides simple control over timeouts
|
||||
> and cancelation and ensures that critical values like security
|
||||
> credentials transit Go programs properly.
|
||||
|
||||
# A saner take on this which I as a Go noob agree with
|
||||
|
||||
- Context should go away for Go 2[^1]
|
||||
|
||||
# Footnotes
|
||||
|
||||
[^1]: <https://faiface.github.io/post/context-should-go-away-go2/>
|
16
content/wiki/20200922160850-destructuring.md
Normal file
16
content/wiki/20200922160850-destructuring.md
Normal file
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
date: 2020-09-22
|
||||
id: 53649586-d844-427a-a91b-0a353631cedc
|
||||
title: JavaScript Destructuring
|
||||
---
|
||||
|
||||
# Variants
|
||||
|
||||
- [Destructuring Arrays](20201103111509-destructuring_arrays)
|
||||
- [Destructuring Objects](20201103111746-destructuring_objects)
|
||||
- [Destructuring Iterables](20201103112001-destructuring_iterables)
|
||||
|
||||
# Default values
|
||||
|
||||
- [Destructuring Default
|
||||
Values](20201103113124-destructuring_default_values)
|
12
content/wiki/20200922162003-parameter_default_values.md
Normal file
12
content/wiki/20200922162003-parameter_default_values.md
Normal file
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
date: 2020-09-22
|
||||
id: d30a86d5-3788-47d0-a749-08e7edce2efd
|
||||
title: JavaScript Parameter default values
|
||||
---
|
||||
|
||||
# ES6
|
||||
|
||||
``` javascript
|
||||
function foo(x=0, y=0) {
|
||||
}
|
||||
```
|
26
content/wiki/20200922162127-named_parameters.md
Normal file
26
content/wiki/20200922162127-named_parameters.md
Normal file
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
date: 2020-09-22
|
||||
id: dedc9e64-fe57-4c60-95b9-7df6201f4949
|
||||
title: JavaScript Named parameters
|
||||
---
|
||||
|
||||
# Introduction
|
||||
|
||||
Introduced with [ES6](20201030093404-es6)
|
||||
|
||||
# Syntax
|
||||
|
||||
``` javascript
|
||||
function selectEntries({ start=0, end=-1, step=1 } = {}) {
|
||||
console.log(start)
|
||||
console.log(end)
|
||||
console.log(step)
|
||||
}
|
||||
|
||||
selectEntries()
|
||||
```
|
||||
|
||||
# See also
|
||||
|
||||
- [Rest Operator (…) in Object
|
||||
Destructuring](20201103111357-rest_operator_in_object_destructuring)
|
32
content/wiki/20200922162500-rest_parameters.md
Normal file
32
content/wiki/20200922162500-rest_parameters.md
Normal file
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
date: 2020-09-22
|
||||
id: 4236e165-bf8b-45fd-9a4c-6cbb66916c45
|
||||
title: JavaScript Rest Parameters
|
||||
---
|
||||
|
||||
# Introduction
|
||||
|
||||
Introduced in [ES6](20201030093404-es6)
|
||||
|
||||
# Syntax
|
||||
|
||||
``` javascript
|
||||
function logAllArguments(...args) {
|
||||
for (const arg of args) {
|
||||
console.log(arg);
|
||||
}
|
||||
}
|
||||
|
||||
logAllArguments(1, 2, 3)
|
||||
```
|
||||
|
||||
``` javascript
|
||||
function logAllArguments(pattern, ...args) {
|
||||
console.log(pattern)
|
||||
for (const arg of args) {
|
||||
console.log(arg);
|
||||
}
|
||||
}
|
||||
|
||||
logAllArguments("asdf", 1, 2, 3)
|
||||
```
|
24
content/wiki/20200922164416-numbers.md
Normal file
24
content/wiki/20200922164416-numbers.md
Normal file
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
date: 2020-09-22
|
||||
id: c613c25d-3bbe-45ca-9034-b7d602770cea
|
||||
title: JavaScript Numbers
|
||||
---
|
||||
|
||||
# Numbers
|
||||
|
||||
- [Fractional Numbers](20201116163755-fractional_numbers)
|
||||
|
||||
# Notations
|
||||
|
||||
- [Scientific Notation](20201116163844-scientific_notation)
|
||||
- [Binary Notation](20201116164748-binary_notation)
|
||||
- [Octal Notation](20201116164828-octal_notation)
|
||||
|
||||
# Special Numbers
|
||||
|
||||
- [Infinity](20201116163925-infinity)
|
||||
- [NaN](20201116164007-nan)
|
||||
|
||||
# Size
|
||||
|
||||
JavaScript uses 64 bits to store number values
|
31
content/wiki/20200922164551-strings.md
Normal file
31
content/wiki/20200922164551-strings.md
Normal file
|
@ -0,0 +1,31 @@
|
|||
---
|
||||
date: 2020-09-22
|
||||
id: 02b70a4e-8f42-4de2-a536-dd42a42f7b47
|
||||
title: JavaScript Strings
|
||||
---
|
||||
|
||||
- [String Prototype
|
||||
Methods](20201112095341-javascript_string_prototype_methods)
|
||||
- [String Literals](20201112100548-javascript_string_literals)
|
||||
- [String Escapes](20201112101218-javascript_string_escapes)
|
||||
- [Unicode](20201112101637-unicode)
|
||||
- [String Iteration](20201112101851-javascript_string_iteration)
|
||||
- [String To Array
|
||||
Conversion](20201112102537-javascript_string_to_array_conversion)
|
||||
|
||||
# Syntax
|
||||
|
||||
## Regular characters
|
||||
|
||||
``` javascript
|
||||
console.log(`Down on the sea`)
|
||||
console.log("Lie on the ocean")
|
||||
console.log('Float on the ocean')
|
||||
```
|
||||
|
||||
## Escaped characters
|
||||
|
||||
``` javascript
|
||||
console.log("This is the first line\nAnd this is the second")
|
||||
console.log("A newline character is written like \"\\n\".")
|
||||
```
|
40
content/wiki/20200922164727-booleans.md
Normal file
40
content/wiki/20200922164727-booleans.md
Normal file
|
@ -0,0 +1,40 @@
|
|||
---
|
||||
date: 2020-09-22
|
||||
id: 19822398-201e-426a-86f0-48ef5a09acda
|
||||
title: JavaScript Booleans
|
||||
---
|
||||
|
||||
# Syntax
|
||||
|
||||
``` javascript
|
||||
console.log(3 > 2)
|
||||
console.log(3 < 2)
|
||||
```
|
||||
|
||||
Strings can also be compared
|
||||
|
||||
``` javascript
|
||||
console.log("Aardvark" < "Zoroaster")
|
||||
```
|
||||
|
||||
Uppercase characters are always less than lower case characters, so "Z"
|
||||
\< "a". Non alphabetic characters are less than alphabetic characters
|
||||
|
||||
``` javascript
|
||||
console.log("Zebra" < "aardvark")
|
||||
console.log("!" < "aardvark")
|
||||
console.log("!" < "Zebra")
|
||||
console.log("3" < "Zebra")
|
||||
console.log("!" < "3")
|
||||
```
|
||||
|
||||
## Empty values
|
||||
|
||||
There are two special empty values, null & undefined that denote the
|
||||
absence of any meaningful value. They can be used interchangeably and
|
||||
are an [accident of JavaScripts
|
||||
design](https://medium.com/@stephenthecurt/a-brief-history-of-null-and-undefined-in-javascript-c283caab662e).
|
||||
|
||||
``` javascript
|
||||
console.log(null == undefined);
|
||||
```
|
16
content/wiki/20200922164830-empty_values.md
Normal file
16
content/wiki/20200922164830-empty_values.md
Normal file
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
date: 2020-09-22
|
||||
id: e250130b-d112-4557-8ac1-77f40608d22c
|
||||
title: Empty values
|
||||
---
|
||||
|
||||
# Syntax
|
||||
|
||||
There are two special empty values, null & undefined that denote the
|
||||
absence of any meaningful value. They can be used interchangeably and
|
||||
are an [accident of JavaScripts
|
||||
design](https://medium.com/@stephenthecurt/a-brief-history-of-null-and-undefined-in-javascript-c283caab662e).
|
||||
|
||||
``` javascript
|
||||
console.log(null == undefined);
|
||||
```
|
45
content/wiki/20200923144022-closures.md
Normal file
45
content/wiki/20200923144022-closures.md
Normal file
|
@ -0,0 +1,45 @@
|
|||
---
|
||||
date: 2020-09-23
|
||||
id: 8353cf5c-2d2d-480a-b957-0e90da847e1c
|
||||
title: Rust Closures
|
||||
---
|
||||
|
||||
# Syntax
|
||||
|
||||
## Long
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let double_closure = |num: u32| -> u32 { 2 * num };
|
||||
|
||||
println!("2 times 3 = {}", double_closure(3));
|
||||
}
|
||||
```
|
||||
|
||||
## Abbreviated
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let double_closure = |num| 2 * num;
|
||||
|
||||
println!("2 times 3 = {}", double_closure(3));
|
||||
}
|
||||
```
|
||||
|
||||
# Closure variable scope
|
||||
|
||||
Unlike [Rust functions](20200827170931-functions_macros) Closures can
|
||||
capture their environment and access variables from the scope in which
|
||||
they're defined:
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let x = 4;
|
||||
|
||||
let equal_to_x = |z| z == x;
|
||||
|
||||
let y = 4;
|
||||
|
||||
assert!(equal_to_x(y));
|
||||
}
|
||||
```
|
141
content/wiki/20200923150006-iterators.md
Normal file
141
content/wiki/20200923150006-iterators.md
Normal file
|
@ -0,0 +1,141 @@
|
|||
---
|
||||
date: 2020-09-23
|
||||
id: a01bfc26-dece-4741-829b-d164ba9522bb
|
||||
title: Rust Iterators
|
||||
---
|
||||
|
||||
# Syntax
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let v1 = vec![1, 2, 3];
|
||||
|
||||
let v1_iter = v1.iter();
|
||||
|
||||
for val in v1_iter {
|
||||
println!("Got: {}", val);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# Iterator Trait
|
||||
|
||||
All iterators implement a [trait](20200917163203-traits) named
|
||||
[Iterator](https://doc.rust-lang.org/std/iter/trait.Iterator.html)
|
||||
|
||||
``` rust
|
||||
#![allow(unused)]
|
||||
fn main() {
|
||||
pub trait Iterator {
|
||||
type Item;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item>;
|
||||
|
||||
// methods with default implementations elided
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# Iterator methods
|
||||
|
||||
## next
|
||||
|
||||
``` rust
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn iterator_demonstration() {
|
||||
let v1 = vec![1, 2, 3];
|
||||
|
||||
let mut v1_iter = v1.iter();
|
||||
|
||||
assert_eq!(v1_iter.next(), Some(&1));
|
||||
assert_eq!(v1_iter.next(), Some(&2));
|
||||
assert_eq!(v1_iter.next(), Some(&3));
|
||||
assert_eq!(v1_iter.next(), None);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
|
||||
## sum
|
||||
|
||||
``` rust
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn iterator_sum() {
|
||||
let v1 = vec![1, 2, 3];
|
||||
|
||||
let v1_iter = v1.iter();
|
||||
|
||||
let total: i32 = v1_iter.sum();
|
||||
|
||||
assert_eq!(total, 6);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
|
||||
# Methods that produce other Iterators
|
||||
|
||||
By their nature iterators are lazy so the following won't work:
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let v1: Vec<i32> = vec![1, 2, 3];
|
||||
|
||||
v1.iter().map(|x| x + 1);
|
||||
}
|
||||
```
|
||||
|
||||
The Iterator must be consumed, using the
|
||||
[collect](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.collect)
|
||||
method:
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let v1: Vec<i32> = vec![1, 2, 3];
|
||||
|
||||
let v2: Vec<_> = v1.iter().map(|x| x + 1).collect();
|
||||
|
||||
assert_eq!(v2, vec![2, 3, 4]);
|
||||
}
|
||||
```
|
||||
|
||||
# Creating your own Iterators
|
||||
|
||||
``` rust
|
||||
struct Counter {
|
||||
count: u32,
|
||||
}
|
||||
|
||||
impl Counter {
|
||||
fn new() -> Counter {
|
||||
Counter { count: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for Counter {
|
||||
type Item = u32;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.count < 5 {
|
||||
self.count += 1;
|
||||
Some(self.count)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let counter = Counter::new();
|
||||
|
||||
for val in counter {
|
||||
println!("Got: {}", val);
|
||||
}
|
||||
}
|
||||
```
|
40
content/wiki/20200923153425-number.md
Normal file
40
content/wiki/20200923153425-number.md
Normal file
|
@ -0,0 +1,40 @@
|
|||
---
|
||||
date: 2020-09-23
|
||||
id: adb898a3-6623-4bd5-92e6-408287d8cb31
|
||||
title: JavaScript Number library
|
||||
---
|
||||
|
||||
# ES6
|
||||
|
||||
## .EPSILON
|
||||
|
||||
Compares floating point numbers with a tolerance for rounding errors.
|
||||
|
||||
## .isInteger(num)
|
||||
|
||||
``` javascript
|
||||
console.log(Number.isInteger(1.05)) // false
|
||||
console.log(Number.isInteger(1)) // true
|
||||
console.log(Number.isInteger(-3.1)) // false
|
||||
console.log(Number.isInteger(-3)) // true
|
||||
```
|
||||
|
||||
## .isNaN
|
||||
|
||||
Checks whether num is the value NaN. In contrast to the global function
|
||||
isNaN(), it doesn’t coerce its argument to a number and is therefore
|
||||
safer for non-numbers:
|
||||
|
||||
``` javascript
|
||||
console.log(isNaN('???')) // true
|
||||
console.log(Number.isNaN('???')) // false
|
||||
```
|
||||
|
||||
## .isFinite
|
||||
|
||||
Determines whether the passed value is a finite number
|
||||
|
||||
``` javascript
|
||||
console.log(Number.isFinite(Infinity)) // false
|
||||
console.log(Number.isFinite(123)) // true
|
||||
```
|
43
content/wiki/20200923153614-math.md
Normal file
43
content/wiki/20200923153614-math.md
Normal file
|
@ -0,0 +1,43 @@
|
|||
---
|
||||
date: 2020-09-23
|
||||
id: 1accac75-7a5c-4847-977a-f0ae63454820
|
||||
title: JavaScript Math library
|
||||
---
|
||||
|
||||
# ES6
|
||||
|
||||
## .sign(x)
|
||||
|
||||
### Returns
|
||||
|
||||
- -1 if x is a negative number (including -Infinity).
|
||||
- 0 if x is zero4.
|
||||
- +1 if x is a positive number (including Infinity).
|
||||
- NaN if x is NaN or not a number.
|
||||
|
||||
``` javascript
|
||||
console.log(Math.sign(-8)) // -a
|
||||
console.log(Math.sign(3)) // 1
|
||||
console.log(Math.sign(0)) // 0
|
||||
console.log(Math.sign(NaN)) // NaN
|
||||
console.log(Math.sign(-Infinity)) // -1
|
||||
console.log(Math.sign(Infinity)) // 1
|
||||
```
|
||||
|
||||
## .trunc(x)
|
||||
|
||||
``` javascript
|
||||
console.log(Math.trunc(3.1)) // 3
|
||||
console.log(Math.trunc(3.9)) // 3
|
||||
console.log(Math.trunc(-3.1)) // 3
|
||||
console.log(Math.trunc(-3.9)) // 3
|
||||
```
|
||||
|
||||
## .cbrt(x)
|
||||
|
||||
Returns the cube root of x:
|
||||
|
||||
``` javascript
|
||||
console.log(Math.cbrt(8)) // 2
|
||||
console.log(Math.cbrt(27)) // 3
|
||||
```
|
47
content/wiki/20200928193245-embedding.md
Normal file
47
content/wiki/20200928193245-embedding.md
Normal file
|
@ -0,0 +1,47 @@
|
|||
---
|
||||
date: 2020-09-28
|
||||
id: 8f08356d-b0dc-465b-b7f5-5522b5133916
|
||||
title: Golang Embedding
|
||||
---
|
||||
|
||||
# Description
|
||||
|
||||
[Embedding](https://golang.org/doc/effective_go.html#embedding) is Gos
|
||||
answer to subclasses. There's one caveat:
|
||||
|
||||
> There's an important way in which embedding differs from subclassing.
|
||||
> When we embed a type, the methods of that type become methods of the
|
||||
> outer type, but when they are invoked the receiver of the method is
|
||||
> the inner type, not the outer one.
|
||||
|
||||
# Interfaces
|
||||
|
||||
``` go
|
||||
type Reader interface {
|
||||
Read(p []byte) (n int, err error)
|
||||
}
|
||||
|
||||
type Writer interface {
|
||||
Write(p []byte) (n int, err error)
|
||||
}
|
||||
|
||||
type ReadWriter interface {
|
||||
Reader
|
||||
Writer
|
||||
}
|
||||
```
|
||||
|
||||
`ReadWriter` "extends" `Reader` & `Writer` in the example above.
|
||||
|
||||
# Structs
|
||||
|
||||
``` go
|
||||
type ReadWriter struct {
|
||||
*Reader // *bufio.Reader
|
||||
*Writer // *bufio.Writer
|
||||
}
|
||||
|
||||
func (rw *ReadWriter) Read(p []byte) (n int, err error) {
|
||||
return rw.reader.Read(p)
|
||||
}
|
||||
```
|
86
content/wiki/20200929135609-box_t.md
Normal file
86
content/wiki/20200929135609-box_t.md
Normal file
|
@ -0,0 +1,86 @@
|
|||
---
|
||||
date: 2020-09-29
|
||||
id: d20e0dd7-ac1d-4dbb-b4e7-a6780b77bd69
|
||||
title: Box\<T\>
|
||||
---
|
||||
|
||||
# Introduction
|
||||
|
||||
Boxes allow you to store data on the heap rather than the stack. What
|
||||
remains on the stack is the pointer to the heap data.
|
||||
|
||||
Boxes don’t have performance overhead, other than storing their data on
|
||||
the heap instead of on the stack. But they don’t have many extra
|
||||
capabilities either. There are three typical user cases for Boxes:
|
||||
|
||||
- When you have a type whose size can’t be known at compile time and
|
||||
you want to use a value of that type in a context that requires an
|
||||
exact size
|
||||
- When you have a large amount of data and you want to transfer
|
||||
ownership but ensure the data won’t be copied when you do so
|
||||
- When you want to own a value and you care only that it’s a type that
|
||||
implements a particular trait rather than being of a specific type
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let b = Box::new(5);
|
||||
println!("b = {}", b);
|
||||
}
|
||||
```
|
||||
|
||||
# Reason to choose Box\<T\>
|
||||
|
||||
`Box<T>` allows immutable or mutable borrows checked at compile time;
|
||||
[Rc\<T\>](20200929145534-rc_t) allows only immutable borrows checked at
|
||||
compile time; [RefCell\<T\>](20200929152628-refcell_t) allows immutable
|
||||
or mutable borrows checked at runtime.
|
||||
|
||||
# Usercases
|
||||
|
||||
## Type whose size can't be known at compile time
|
||||
|
||||
When you have a type whose size can’t be known at compile time and you
|
||||
want to use a value of that type in a context that requires an exact
|
||||
size.
|
||||
|
||||
The following won't compile as the `List` type doesn't have a known
|
||||
size:
|
||||
|
||||
``` rust
|
||||
enum List {
|
||||
Cons(i32, List),
|
||||
Nil,
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
|
||||
This won't fly either:
|
||||
|
||||
``` rust
|
||||
enum List {
|
||||
Cons(i32, List),
|
||||
Nil,
|
||||
}
|
||||
|
||||
use crate::List::{Cons, Nil};
|
||||
|
||||
fn main() {
|
||||
let list = Cons(1, Cons(2, Cons(3, Nil)));
|
||||
}
|
||||
```
|
||||
|
||||
With pointers all things are possible, huzzah:
|
||||
|
||||
``` rust
|
||||
enum List {
|
||||
Cons(i32, Box<List>),
|
||||
Nil,
|
||||
}
|
||||
|
||||
use crate::List::{Cons, Nil};
|
||||
|
||||
fn main() {
|
||||
let _list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
|
||||
}
|
||||
```
|
109
content/wiki/20200929141711-deref_trait.md
Normal file
109
content/wiki/20200929141711-deref_trait.md
Normal file
|
@ -0,0 +1,109 @@
|
|||
---
|
||||
date: 2020-09-29
|
||||
id: d2d028c8-733f-4cdb-b096-89cf8b3de961
|
||||
title: Deref Trait
|
||||
---
|
||||
|
||||
# Introduction
|
||||
|
||||
Implementing the `Deref` trait allows you to customize the behavior of
|
||||
the *dereference operator*, \* (as opposed to the multiplication or glob
|
||||
operator). By implementing `Deref` in such a way that a smart pointer
|
||||
can be treated like a regular reference, you can write code that
|
||||
operates on references and use that code with smart pointers too:
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let x = 5;
|
||||
let y = &x;
|
||||
|
||||
assert_eq!(5, x);
|
||||
assert_eq!(5, *y);
|
||||
}
|
||||
```
|
||||
|
||||
# Box
|
||||
|
||||
A [Box\<T\>](20200929135609-box_t) can also be used:
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let x = 5;
|
||||
let y = Box::new(x);
|
||||
|
||||
assert_eq!(5, x);
|
||||
assert_eq!(5, *y);
|
||||
}
|
||||
```
|
||||
|
||||
# Deref Trait
|
||||
|
||||
``` rust
|
||||
use std::ops::Deref;
|
||||
|
||||
impl<T> Deref for MyBox<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
struct MyBox<T>(T);
|
||||
|
||||
impl<T> MyBox<T> {
|
||||
fn new(x: T) -> MyBox<T> {
|
||||
MyBox(x)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 5;
|
||||
let y = MyBox::new(x);
|
||||
|
||||
assert_eq!(5, x);
|
||||
assert_eq!(5, *y);
|
||||
}
|
||||
```
|
||||
|
||||
# Deref Coercion
|
||||
|
||||
*Deref coercion* is a convenience that Rust performs on arguments to
|
||||
functions and methods. Deref coercion works only on types that implement
|
||||
the Deref trait. Deref coercion converts such a type into a reference to
|
||||
another type. For example, deref coercion can convert `&String` to
|
||||
`&str` because `String` implements the `Deref` trait such that it
|
||||
returns `str`. Deref coercion happens automatically when we pass a
|
||||
reference to a particular type’s value as an argument to a function or
|
||||
method that doesn’t match the parameter type in the function or method
|
||||
definition. A sequence of calls to the `deref` method converts the type
|
||||
we provided into the type the parameter needs.
|
||||
|
||||
``` rust
|
||||
use std::ops::Deref;
|
||||
|
||||
impl<T> Deref for MyBox<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
struct MyBox<T>(T);
|
||||
|
||||
impl<T> MyBox<T> {
|
||||
fn new(x: T) -> MyBox<T> {
|
||||
MyBox(x)
|
||||
}
|
||||
}
|
||||
|
||||
fn hello(name: &str) {
|
||||
println!("Hello, {}!", name);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let m = MyBox::new(String::from("Rust"));
|
||||
hello(&m);
|
||||
}
|
||||
```
|
34
content/wiki/20200929142932-drop_trait.md
Normal file
34
content/wiki/20200929142932-drop_trait.md
Normal file
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
date: 2020-09-29
|
||||
id: a5820942-f47a-4a5e-ba83-33916cc24674
|
||||
title: Drop Trait
|
||||
---
|
||||
|
||||
# Introduction
|
||||
|
||||
`Drop` lets you customize what happens when a value is about to go out
|
||||
of scope, ie: to release resources like files or network connections.
|
||||
|
||||
# Example
|
||||
|
||||
``` rust
|
||||
struct CustomSmartPointer {
|
||||
data: String,
|
||||
}
|
||||
|
||||
impl Drop for CustomSmartPointer {
|
||||
fn drop(&mut self) {
|
||||
println!("Dropping CustomSmartPointer with data `{}`!", self.data);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _c = CustomSmartPointer {
|
||||
data: String::from("my stuff"),
|
||||
};
|
||||
let _d = CustomSmartPointer {
|
||||
data: String::from("other stuff"),
|
||||
};
|
||||
println!("CustomSmartPointers created.");
|
||||
}
|
||||
```
|
63
content/wiki/20200929145534-rc_t.md
Normal file
63
content/wiki/20200929145534-rc_t.md
Normal file
|
@ -0,0 +1,63 @@
|
|||
---
|
||||
date: 2020-09-29
|
||||
id: 13459bc1-66f2-4eed-b987-061bd0fbeb1c
|
||||
title: Rc\<T\>
|
||||
---
|
||||
|
||||
# Introduction
|
||||
|
||||
In the majority of cases, ownership is clear: you know exactly which
|
||||
variable owns a given value. However, there are cases when a single
|
||||
value might have multiple owners. For example, in graph data structures,
|
||||
multiple edges might point to the same node, and that node is
|
||||
conceptually owned by all of the edges that point to it. A node
|
||||
shouldn’t be cleaned up unless it doesn’t have any edges pointing to it.
|
||||
|
||||
To enable multiple ownership, Rust has a type called `Rc<T>`, which is
|
||||
an abbreviation for reference counting. The `Rc<T>` type keeps track of
|
||||
the number of references to a value which determines whether or not a
|
||||
value is still in use. If there are zero references to a value, the
|
||||
value can be cleaned up without any references becoming invalid.
|
||||
|
||||
# Reason to choose Rc\<T\>
|
||||
|
||||
`Rc<T>` enables multiple owners of the same data;
|
||||
[Box\<T\>](20200929135609-box_t) and
|
||||
[RefCell\<T\>](20200929152628-refcell_t) have single owners.
|
||||
|
||||
# Example
|
||||
|
||||
This won't compile because b & c both share ownership of a:
|
||||
|
||||
``` rust
|
||||
enum List {
|
||||
Cons(i32, Box<List>),
|
||||
Nil,
|
||||
}
|
||||
|
||||
use crate::List::{Cons, Nil};
|
||||
|
||||
fn main() {
|
||||
let a = Cons(5, Box::new(Cons(10, Box::new(Nil))));
|
||||
let _b = Cons(3, Box::new(a));
|
||||
let _c = Cons(4, Box::new(a));
|
||||
}
|
||||
```
|
||||
|
||||
The solution:
|
||||
|
||||
``` rust
|
||||
enum List {
|
||||
Cons(i32, Rc<List>),
|
||||
Nil,
|
||||
}
|
||||
|
||||
use crate::List::{Cons, Nil};
|
||||
use std::rc::Rc;
|
||||
|
||||
fn main() {
|
||||
let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
|
||||
let _b = Cons(3, Rc::clone(&a));
|
||||
let _c = Cons(4, Rc::clone(&a));
|
||||
}
|
||||
```
|
63
content/wiki/20200929152628-refcell_t.md
Normal file
63
content/wiki/20200929152628-refcell_t.md
Normal file
|
@ -0,0 +1,63 @@
|
|||
---
|
||||
date: 2020-09-29
|
||||
id: 16e7cc98-b9fb-40c3-b2cf-41d3035275be
|
||||
title: RefCell\<T\>
|
||||
---
|
||||
|
||||
# Introduction
|
||||
|
||||
*Interior mutability* is a design pattern in Rust that allows you to
|
||||
mutate data even when there are immutable references to that data;
|
||||
normally, this action is disallowed by the borrowing rules. To mutate
|
||||
data, the pattern uses `unsafe` code inside a data structure to bend
|
||||
Rust’s usual rules that govern mutation and borrowing. We can use types
|
||||
that use the interior mutability pattern when we can ensure that the
|
||||
borrowing rules will be followed at runtime, even though the compiler
|
||||
can’t guarantee that. The `unsafe` code involved is then wrapped in a
|
||||
safe API, and the outer type is still immutable.
|
||||
|
||||
# Reason to choose RefCell\<T\>
|
||||
|
||||
Because `RefCell<T>` allows mutable borrows checked at runtime, you can
|
||||
mutate the value inside the `RefCell<T>` even when the `RefCell<T>` is
|
||||
immutable.
|
||||
|
||||
# Example
|
||||
|
||||
This won't compile:
|
||||
|
||||
``` rust
|
||||
fn main() {
|
||||
let x = 5;
|
||||
let y = &mut x;
|
||||
}
|
||||
```
|
||||
|
||||
This will:
|
||||
|
||||
``` rust
|
||||
#[derive(Debug)]
|
||||
enum List {
|
||||
Cons(Rc<RefCell<i32>>, Rc<List>),
|
||||
Nil,
|
||||
}
|
||||
|
||||
use crate::List::{Cons, Nil};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
fn main() {
|
||||
let value = Rc::new(RefCell::new(5));
|
||||
|
||||
let a = Rc::new(Cons(Rc::clone(&value), Rc::new(Nil)));
|
||||
|
||||
let b = Cons(Rc::new(RefCell::new(3)), Rc::clone(&a));
|
||||
let c = Cons(Rc::new(RefCell::new(4)), Rc::clone(&a));
|
||||
|
||||
*value.borrow_mut() += 10;
|
||||
|
||||
println!("a after = {:?}", a);
|
||||
println!("b after = {:?}", b);
|
||||
println!("c after = {:?}", c);
|
||||
}
|
||||
```
|
49
content/wiki/20200929161126-basic_annotations.md
Normal file
49
content/wiki/20200929161126-basic_annotations.md
Normal file
|
@ -0,0 +1,49 @@
|
|||
---
|
||||
date: 2020-09-29
|
||||
id: 89671783-1085-4a00-9147-a377db9b19bc
|
||||
title: TypeScript
|
||||
---
|
||||
|
||||
# Basic Annotations
|
||||
|
||||
- [Primitive Types](20200929161544-primitive_types)
|
||||
- [Arrays](20200929162129-arrays)
|
||||
- [Inline Type Annotation](20200929162417-inline_type_annotation)
|
||||
|
||||
# Type System
|
||||
|
||||
- [Ambient Declarations](20200930105954-ambient_declarations)
|
||||
- [Interfaces](20200929162220-interfaces)
|
||||
- [Enums](20200930110721-typescript_enums)
|
||||
- [lib.d.ts](20201001105545-lib_d_ts)
|
||||
- [Functions](20201001110806-typescript_functions)
|
||||
- [Callable](20201001112126-typescript_callable)
|
||||
- [Type Assertion](20201002101745-typescript_type_assertion)
|
||||
- [Type Guard](20201002102455-typescript_type_guard)
|
||||
- [Literal Types](20201002103357-typescript_literal_types)
|
||||
- [Readonly](20201005171253-readonly)
|
||||
- [Generics](20200929163051-typescript_generics)
|
||||
- [Intersection Type](20200929163316-typescript_intersection_type)
|
||||
- [Tuple Type](20200929163624-typescript_tuple_type)
|
||||
- [TypeScript Type Alias](20200929163825-typescript_type_alias)
|
||||
- [Never Type](20201007095614-typescript_never_type)
|
||||
- [Index Signatures](20201008092225-index_signatures)
|
||||
- [Classes](20201009104411-typescript_classes)
|
||||
|
||||
## Unions
|
||||
|
||||
- [Union Type](20200929163219-typescript_union_type)
|
||||
- [Discriminated Union](20201007101133-typescript_discriminated_union)
|
||||
|
||||
# Related pages
|
||||
|
||||
- [JavaScript](20200613170905-javascript)
|
||||
|
||||
# Books
|
||||
|
||||
- [TypeScript Deep Dive](https://basarat.gitbook.io/typescript/)
|
||||
- [Style Guide](https://basarat.gitbook.io/typescript/styleguide)
|
||||
|
||||
# Changes
|
||||
|
||||
- [TypeScript 4.0](20201009104050-typescript_4_0)
|
67
content/wiki/20200929161126-typescript.md
Normal file
67
content/wiki/20200929161126-typescript.md
Normal file
|
@ -0,0 +1,67 @@
|
|||
---
|
||||
date: 2020-09-29
|
||||
id: 547d6700-cedd-4273-9f12-1fd4da96b695
|
||||
title: TypeScript
|
||||
---
|
||||
|
||||
# Types
|
||||
|
||||
- [Arrays](20200929162129-arrays)
|
||||
- [Enums](20200930110721-typescript_enums)
|
||||
- [Generics](20200929163051-typescript_generics)
|
||||
- [Intersection Type](20200929163316-typescript_intersection_type)
|
||||
- [Literal Types](20201002103357-typescript_literal_types)
|
||||
- [Mapped Type](20201124085335-typescript_mapped_type)
|
||||
- [Never Type](20201007095614-typescript_never_type)
|
||||
- [Primitive Types](20200929161544-primitive_types)
|
||||
- [Recursive Conditional
|
||||
Types](20201125085727-typescript_recursive_conditional_types)
|
||||
- [Tuple Type](20200929163624-typescript_tuple_type)
|
||||
- [Union Type](20200929163219-typescript_union_type)
|
||||
|
||||
# Objects
|
||||
|
||||
- [Classes](20201009104411-typescript_classes)
|
||||
- [Inline Type Annotation](20200929162417-inline_type_annotation)
|
||||
- [Interfaces](20200929162220-interfaces)
|
||||
|
||||
# Functions
|
||||
|
||||
- [Functions](20201001110806-typescript_functions)
|
||||
|
||||
# Declarations
|
||||
|
||||
- [Ambient Declarations](20200930105954-ambient_declarations)
|
||||
- [lib.d.ts](20201001105545-lib_d_ts)
|
||||
|
||||
# Syntax
|
||||
|
||||
- [Callable](20201001112126-typescript_callable)
|
||||
- [Discriminated Union](20201007101133-typescript_discriminated_union)
|
||||
- [Index Signatures](20201008092225-index_signatures)
|
||||
- [Readonly](20201005171253-readonly)
|
||||
- [Type Alias](20200929163825-typescript_type_alias)
|
||||
- [Type Assertion](20201002101745-typescript_type_assertion)
|
||||
- [Type Guard](20201002102455-typescript_type_guard)
|
||||
|
||||
# Clauses
|
||||
|
||||
- [as](20201124095453-typescript_as_clause)
|
||||
|
||||
# Keywords
|
||||
|
||||
- [in](20201124090450-typescript_in_operator)
|
||||
|
||||
# Configuration
|
||||
|
||||
- [Flags](20201127101043-typescript_flags)
|
||||
|
||||
# Books
|
||||
|
||||
- [TypeScript Deep Dive](https://basarat.gitbook.io/typescript/)
|
||||
- [Style Guide](https://basarat.gitbook.io/typescript/styleguide)
|
||||
|
||||
# Changes
|
||||
|
||||
- [4.0](20201009104050-typescript_4_0)
|
||||
- [4.1](20201123094735-typescript_4_1)
|
35
content/wiki/20200929161544-primitive_types.md
Normal file
35
content/wiki/20200929161544-primitive_types.md
Normal file
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
date: 2020-09-29
|
||||
id: 8809980a-615d-453f-bc63-2f890fca03b8
|
||||
title: TypeScript primitive types
|
||||
---
|
||||
|
||||
# Syntax
|
||||
|
||||
## Number
|
||||
|
||||
``` typescript
|
||||
var num: number
|
||||
num = 123
|
||||
num = 123.24
|
||||
num = '123' / Error
|
||||
```
|
||||
|
||||
## String
|
||||
|
||||
``` typescript
|
||||
var str: string
|
||||
|
||||
str = '123'
|
||||
str = 123 // Error
|
||||
```
|
||||
|
||||
## Boolean
|
||||
|
||||
``` typescript
|
||||
var bool: boolean
|
||||
|
||||
bool = true
|
||||
bool = false
|
||||
bool = 'tralala' // Error
|
||||
```
|
21
content/wiki/20200929162129-arrays.md
Normal file
21
content/wiki/20200929162129-arrays.md
Normal file
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
date: 2020-09-29
|
||||
id: aea39282-589d-49ab-8b50-c55c7681f500
|
||||
title: TypeScript Arrays
|
||||
---
|
||||
|
||||
# Syntax
|
||||
|
||||
``` typescript
|
||||
var boolArray: boolean[];
|
||||
|
||||
boolArray = [true, false];
|
||||
console.log(boolArray[0]); // true
|
||||
console.log(boolArray.length); // 2
|
||||
boolArray[1] = true;
|
||||
boolArray = [false, false];
|
||||
|
||||
boolArray[0] = 'false'; // Error!
|
||||
boolArray = 'false'; // Error!
|
||||
boolArray = [true, 'false']; // Error!
|
||||
```
|
40
content/wiki/20200929162220-interfaces.md
Normal file
40
content/wiki/20200929162220-interfaces.md
Normal file
|
@ -0,0 +1,40 @@
|
|||
---
|
||||
date: 2020-09-29
|
||||
id: 1bdd832a-3dee-4b31-9192-c51cde8a4b66
|
||||
title: TypeScript Interfaces
|
||||
---
|
||||
|
||||
# Example
|
||||
|
||||
``` typescript
|
||||
interface Name {
|
||||
first: string;
|
||||
second: string;
|
||||
}
|
||||
|
||||
var name: Name;
|
||||
name = {
|
||||
first: 'John',
|
||||
second: 'Doe'
|
||||
};
|
||||
|
||||
name = { // Error : `second` is missing
|
||||
first: 'John'
|
||||
};
|
||||
name = { // Error : `second` is the wrong type
|
||||
first: 'John',
|
||||
second: 1337
|
||||
};
|
||||
```
|
||||
|
||||
## Class implementing interface
|
||||
|
||||
``` typescript
|
||||
interface Point {
|
||||
x: number; y: number;
|
||||
}
|
||||
|
||||
class MyPoint implements Point {
|
||||
x: number; y: number; // Same as Point
|
||||
}
|
||||
```
|
26
content/wiki/20200929162417-inline_type_annotation.md
Normal file
26
content/wiki/20200929162417-inline_type_annotation.md
Normal file
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
date: 2020-09-29
|
||||
id: 01e5c8e4-5227-4565-96e5-94a4bb6240ea
|
||||
title: TypeScript Inline Type Annotation
|
||||
---
|
||||
|
||||
# Syntax
|
||||
|
||||
``` typescript
|
||||
var name: {
|
||||
first: string;
|
||||
second: string;
|
||||
};
|
||||
name = {
|
||||
first: 'John',
|
||||
second: 'Doe'
|
||||
};
|
||||
|
||||
name = { // Error : `second` is missing
|
||||
first: 'John'
|
||||
};
|
||||
name = { // Error : `second` is the wrong type
|
||||
first: 'John',
|
||||
second: 1337
|
||||
};
|
||||
```
|
60
content/wiki/20200929163051-typescript_generics.md
Normal file
60
content/wiki/20200929163051-typescript_generics.md
Normal file
|
@ -0,0 +1,60 @@
|
|||
---
|
||||
date: 2020-09-29
|
||||
id: aacdac15-4e00-4d75-9888-79b23bb47498
|
||||
title: TypeScript Generics
|
||||
---
|
||||
|
||||
# Examples
|
||||
|
||||
## Function level
|
||||
|
||||
``` typescript
|
||||
function reverse<T>(items: T[]): T[] {
|
||||
var toreturn = [];
|
||||
for (let i = items.length - 1; i >= 0; i--) {
|
||||
toreturn.push(items[i]);
|
||||
}
|
||||
return toreturn;
|
||||
}
|
||||
|
||||
var sample = [1, 2, 3];
|
||||
var reversed = reverse(sample);
|
||||
console.log(reversed); // 3,2,1
|
||||
|
||||
// Safety!
|
||||
reversed[0] = '1'; // Error!
|
||||
reversed = ['1', '2']; // Error!
|
||||
|
||||
reversed[0] = 1; // Okay
|
||||
reversed = [1, 2]; // Okay
|
||||
```
|
||||
|
||||
## Class level
|
||||
|
||||
``` typescript
|
||||
/** A class definition with a generic parameter */
|
||||
class Queue<T> {
|
||||
private data = [];
|
||||
push(item: T) { this.data.push(item); }
|
||||
pop(): T | undefined { return this.data.shift(); }
|
||||
}
|
||||
|
||||
/** Again sample usage */
|
||||
const queue = new Queue<number>();
|
||||
queue.push(0);
|
||||
queue.push("1"); // ERROR : cannot push a string. Only numbers allowed
|
||||
```
|
||||
|
||||
## Member functions
|
||||
|
||||
``` typescript
|
||||
class Utility {
|
||||
reverse<T>(items: T[]): T[] {
|
||||
var toreturn = [];
|
||||
for (let i = items.length - 1; i >= 0; i--) {
|
||||
toreturn.push(items[i]);
|
||||
}
|
||||
return toreturn;
|
||||
}
|
||||
}
|
||||
```
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue