This type is allocated on the heap and as such is able to store an amount of text that is unknown to us at compile time.
#![allow(unused_variables)] fn main() { let s = String::from("hello"); }
#![allow(unused_variables)] fn main() { let mut s = String::from("hello");
s.push_str(", world!"); // push_str() appends a literal to a String
println!("{}", s); // This will print `hello, world!` }
release memory
#![allow(unused_variables)] fn main() { { let s = String::from("hello"); // s is valid from this point forward
// do stuff with s } // this scope is now over, and s is no // longer valid }
There is a natural point at which we can return the memory our String needs to the operating system: when s goes out of scope. When a variable goes out of scope, Rust calls a special function for us. This function is called drop, and it’s where the author of String can put the code to return the memory. Rust calls drop automatically at the closing curly bracket.
#![allow(unused_variables)] fn main() { let s1 = String::from("hello"); let s2 = s1; //Rust considers s1 to no longer be valid }
actually is a move operation
deep copy use clone
#![allow(unused_variables)] fn main() { let s1 = String::from("hello"); let s2 = s1.clone();
println!("s1 = {}, s2 = {}", s1, s2); }
return value and scope
fn main() { let s1 = gives_ownership(); // gives_ownership moves its return // value into s1
let s2 = String::from("hello"); // s2 comes into scope
let s3 = takes_and_gives_back(s2); // s2 is moved into // takes_and_gives_back, which also // moves its return value into s3 } // Here, s3 goes out of scope and is dropped. s2 goes out of scope but was // moved, so nothing happens. s1 goes out of scope and is dropped.
fn gives_ownership() -> String { // gives_ownership will move its // return value into the function // that calls it
let some_string = String::from("hello"); // some_string comes into scope
some_string // some_string is returned and // moves out to the calling // function }
// takes_and_gives_back will take a String and return one fn takes_and_gives_back(a_string: String) -> String { // a_string comes into // scope
a_string // a_string is returned and moves out to the calling function }
return multiple value use tuple
fn main() { let s1 = String::from("hello");
let (s2, len) = calculate_length(s1);
println!("The length of '{}' is {}.", s2, len); }
fn calculate_length(s: String) -> (String, usize) { let length = s.len(); // len() returns the length of a String
(s, length) }
slice
#![allow(unused_variables)] fn main() { let s = String::from("hello world");
let hello = &s[0..5]; let world = &s[6..11]; }
The start..end syntax is a range that begins at start and continues up to, but not including, end. If we wanted to include end, we can use ..= instead of ..:
#![allow(unused_variables)] fn main() { let s = String::from("hello world");
let mut x = 5; println!("The value of x is: {}", x); x = 6; println!("The value of x is: {}", x);
difference with constant
Not allowed use mut with constants
Declare constants with const keyword, and the type of the value must be annotated
Constants can be declared in any scope
The last difference is that constants may be set only to a constant expression, not the result of a function call or any other value that could only be computed at runtime.
raw identifiers
Sometimes, you may need to use a name that’s a keyword for another purpose. Maybe you need to call a function named match that is coming from a C library, where ‘match’ is not a keyword. To do this, you can use a “raw identifier.” Raw identifiers start with r#:
let r#fn = "this variable is named 'fn' even though that's a keyword";
// call a function named 'match' r#match();
Data Types
Scalar Types
A scalar type represents a single value.
Rust has four primary scalar types: integers, floating-point numbers, Booleans, and characters
integers
Length
Signed
Unsigned
8-bit
i8
u8
16-bit
i16
u16
32-bit
i32
u32
64-bit
i64
u64
128-bit
i128
u128
arch
isize
usize
Additionally, the isize and usize types depend on the kind of computer your program is running on: 64 bits if you’re on a 64-bit architecture and 32 bits if you’re on a 32-bit architecture.
Number literals
Example
Decimal
98_222
Hex
0xff
Octal
0o77
Binary
0b1111_0000
Byte (u8 only)
b’A’
floating-point numbers
fn main() { let x = 2.0; // f64
let y: f32 = 3.0; // f32 }
boolean
true or false that’s a question
characters
Rust’s char type represents a Unicode Scalar Value, which means it can represent a lot more than just ASCII. Accented letters; Chinese, Japanese, and Korean characters; emoji; and zero-width spaces are all valid char values in Rust. Unicode Scalar Values range from U+0000 to U+D7FF and U+E000 to U+10FFFF inclusive.
fn main() { let c = 'z'; let z = 'ℤ'; let heart_eyed_cat = '😻'; }
compound types
Compound types can group multiple values into one type. Rust has two primitive compound types: tuples and arrays.
Tuples
A tuple is a general way of grouping together some number of other values with a variety of types into one compound type. Tuples have a fixed length: once declared, they cannot grow or shrink in size.
fn main() { let a = [1, 2, 3, 4, 5]; let index = 10;
let element = a[index];
println!("The value of element is: {}", element); }
The compilation didn’t produce any errors, but the program resulted in a runtime error and didn’t exit successfully. When you attempt to access an element using indexing, Rust will check that the index you’ve specified is less than the array length. If the index is greater than the length, Rust will panic.
functions
Rust code uses snake case as the conventional style for function and variable names.
fn main() { another_function(5, 6); }
fn another_function(x: i32, y: i32) { println!("The value of x is: {}", x); println!("The value of y is: {}", y); }
return value use ->
fn main() { let x = plus_one(5);
println!("The value of x is: {}", x); }
fn plus_one(x: i32) -> i32 { x + 1 }
comments
same to c language.
// one line comment /* block Comments block Comments */
Doc comments which are parsed into HTML library
control flow
if
fn main() { let number = 3;
if number < 5 { println!("condition was true"); } else { println!("condition was false"); } }
fn main() { let number = 6;
if number % 4 == 0 { println!("number is divisible by 4"); } else if number % 3 == 0 { println!("number is divisible by 3"); } else if number % 2 == 0 { println!("number is divisible by 2"); } else { println!("number is not divisible by 4, 3, or 2"); } }
using with let Because if is an expression, we can use it on the right side of a let statement
fn main() { let condition = true; let number = if condition { 5 } else { 6 };
println!("The value of number is: {}", number); }
loops
loop
The loop keyword tells Rust to execute a block of code over and over again forever or until you explicitly tell it to stop.
fn main() { let mut counter = 0;
let result = loop { counter += 1;
if counter == 10 { break counter * 2; } };
assert_eq!(result, 20); }
while
fn main() { let mut number = 3;
while number != 0 { println!("{}!", number);
number = number - 1; }
println!("LIFTOFF!!!"); }
for
fn main() { let a = [10, 20, 30, 40, 50];
for element in a.iter() { println!("the value is: {}", element); } }
fn main() { for number in (1..4).rev() { println!("{}!", number); } println!("LIFTOFF!!!"); }
macro system
macros look like functions, except that their name ends with a bang ! Rust macros are expanded into abstract syntax trees, rather than string preprocessing, so you don’t get unexpected precedence bugs.
// This is a simple macro named `say_hello`. macro_rules! say_hello { // `()` indicates that the macro takes no argument. () => ( // The macro will expand into the contents of this block. println!("Hello!"); ) }
fn main() { // This call will expand into `println!("Hello");` say_hello!() }
Ethereum has no common functions. It’s a common platform EOS has build-in common functions like crypto, database save development time and effort
Consensus & Governance
Scalability
Dos attack
Graphene
Graphene has been designed especially for transactions (token transfer) and high-throughput in order to compete with Visa and Mastercard.
However, the more we’ve drilled down the Graphene core source code, the more we’ve understood why Dan Larimer left the project and completely switched to EOS. Here are some main issues we’ve found:
① 一个主链可以挂各种平行链,平行链通过转接桥可以接进来。不要求是以太系。btc,EOS通过桥也可以接进来。 ②平行链的安全性可以集中到主链中,形成一个安全池。 ③各个平行链之间可以通过中继链互相连通,包括智能合约的调用。 因此,Polkadot可以让dapp跑自己的平行链,并且具有主链的安全性,这可以解决 one platform for all 的问题,但是如果这个dapp本身对吞吐量要求就特别高的话,那还是得平行链自己来解决,比如EOS。
Rust is a modern systems programming language focusing on safety, speed, and concurrency. It accomplishes these goals by being memory safe without using garbage collection.
Performance
Rust is blazingly fast and memory-efficient: with no runtime or garbage collector, it can power performance-critical services, run on embedded devices, and easily integrate with other languages.
Reliability
Rust’s rich type system and ownership model guarantee memory-safety and thread-safety — and enable you to eliminate many classes of bugs at compile-time.
Productivity
Rust has great documentation, a friendly compiler with useful error messages, and top-notch tooling — an integrated package manager and build tool, smart multi-editor support with auto-completion and type inspections, an auto-formatter, and more.
some tools
cargo: Rust’s compilation manager, package manager, and general-purpose tool
rustc:Rust compiler. Usually we let Cargo invoke the compiler for us
rustdoc:rustdoc can build nicely formatted HTML for us.
curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to sh.rustup.rs:443
solution: take a rest, buy a cup of coffee. and try again a few hours later. maybe 18.00 is ok
add the following line to your ~/.bash_profile:
export PATH="$HOME/.cargo/bin:$PATH"
Cargo: the Rust build tool and package manager
build your project with cargo build
run your project with cargo run
test your project with cargo test
build documentation for your project with cargo doc
publish a library to crates.io with cargo publish
To test that you have Rust and Cargo installed, you can run this in your terminal of choice: cargo --version
You can install a code formatting tool (Rustfmt) with rustup component add rustfmt, and a linting tool (Clippy) with rustup component add clippy.
need update rustup update need uninstall rustup self uninstall
Ownership
Ownership is Rust’s most unique feature, and it enables Rust to make memory safety guarantees without needing a garbage collector. related features: borrowing, slices Rust uses a third approach: memory is managed through a system of ownership with a set of rules that the compiler checks at compile time. None of the ownership features slow down your program while it’s running.
Rules
Each value in Rust has a variable that’s called its owner.
There can only be one owner at a time.
When the owner goes out of scope, the value will be dropped.
many tools come working out-of-the-box, including:
Polkadot connectivity
Hot-swappable, pluggable Consensus
Hot-upgradeable, pluggable STF
Flexible and general sync
Pub/Sub WebSocket JSON-RPC
Light client
Transaction queue
Pervasive, secure networking
JavaScript implementation
Substrate Runtime Module Library (SRML)
Because of Substrate’s novel on-chain upgrade mechanism, you will be able “hot-swap” consensus algorithms or upgrade STFs without the need to hard fork. The latter, a forkless upgrade mechanism was first publicly demonstrated on the Polkadot “Krumme Lanke” testnet on July 17th, 2018, and continues as the PoC-2 testnet at the time of this article’s release.
Several consensus algorithms are supported in the 1.0-beta, with more are coming soon, including:
Substrate combines three new technologies: Rust, WebAssembly and Libp2p in order to create a framework that makes building upgradable, efficient and innovative blockchains easy. In short, Substrate helps you build the best blockchain you can.
AfG is an internal codename “Al’s Finality Gadget” due to @AlistairStewart who invented it
Substrate gives blockchain innovators the framework for maximum freedom with minimal effort. It is highly customisable, adaptable, and made by blockchain developers for blockchain developers. It allows developers to focus their effort on the thing they care most about—the state transition function—while providing them with the networking, consensus and security as well as an upgrade path to interoperability with Polkadot.
Substrate’s revolutionary generality and developability is evidenced through it being used to build four wildly different blockchains including Polkadot and Ethereum 2.0 simultaneously and in a fraction of the time it would otherwise take (an early version of Ethereum 2.0 was prototyped in a few weeks).
Substrate is separated into Substrate Core and Substrate Runtime Module Library (SRML) and comes with a pre-assembled Substrate Node that is simple to configure.
Substrate Core
is the minimal Substrate base for building blockchains. Substrate Core gives you a foundation that is far easier than building a blockchain from scratch, though you don’t get a finished blockchain. It includes:
Pervasive and secure networking via libp2p
Storage
Telemetry
Light client
Block synchronisation
Extensible JSON-RPC API endpoints
Low-level JavaScript utils
Transaction queue and block production mechanism
Sandboxed WebAssembly interpreter
Interchain connectivity via the Polkadot protocol
Crypto primitives library
Chain specification and versioning
Pluggable consensus
Substrate Runtime Module Library (SRML)
The core architecture of Substrate separates the basic functionality of a network blockchain node and the chain-specific implementations by executing the latter in a separate WebAssembly environment. You have absolute freedom to write the chain logic in any language that can compile down to WebAssembly (Rust, C/C++, C#, Go, etc). You can add modules from the Substrate Runtime Module Library, or SRML. With SRML, you can take off-the-shelf components, plug them together, and build a blockchain that does what you want it to do. Modules include:
Accounts & Balances – basic cryptocurrency, including account management and viewing
Consensus – setting and modifying runtime code and storage (i.e. the set of authorities as a list of session keys on-chain), and reporting offline or misbehaving validators
Staking – Proof-of-Stake logic, including both staking and nominating of validator accounts
Timestamp – have your chain know about time
Treasury – decentralised grants, similar to a DAO
So, for example, if you want to create a Proof-of-Stake smart contract blockchain, you would take Substrate Core and plug in the Accounts & Balances, Staking, and Contracts modules. Once Polkadot launches, you could also make it interoperable by plugging it into Polkadot.
Substrate Node
Finally, Substrate Node allows you to deploy a blockchain with maximum ease. Soon you will be able to configure Substrate Node with a JSON file.