Index"Solidity" 1. The layout of a solidity source file "solidity" 2. Structure of the contract
"Solidity" 3. Type "solidity" 4. Unit and global variable "solidity" 5. Expression and control structure "solidity" 6. Contract
"Solidity" 7. Part "solidity" 8. Miscellaneous
expressions and control structures
input parameters and output parameters
Like JavaScript, a function can take arguments as input; Unlike JavaScript and C, they can also return any number of arguments as output. Input Parameters
Input parameters are declared in the same way as variables. As an exception, unused parameters can omit the variable name. For example, suppose we want our contract to accept an external call with two integers, and we'll write the following:
pragma solidity ^0.4.0;
Contract Simple {
function taker (UINT _a, uint _b) {
//does something with _a and _b.
}
}
Output Parameters
Output parameters can be declared with the same syntax after the keyword is returned. For example, suppose we want to return two results: the sum and product of two given integers, then we will write:
pragma solidity ^0.4.0;
Contract Simple {
function arithmetics (UINT _a, UINT _b) returns (UINT o_sum, uint o_product) {
o_sum = _a + _b;
o_product = _a * _b;
}
You can omit the name of an output parameter. You can also specify an output value by using the return statement. The return statement can also return multiple values, see returning multiple values. The return parameter is initialized to zero; If they are not explicitly set, they remain zero.
Input and output parameters can be used as expressions in the body of a function. There, they can also be used on the left side of the task. Control Structure
Most control structures from JavaScript can use solidity, except for switch and Goto. So there are: if, else, while, doing, for, break, continue, return,?:, with the usual semantics known in C or JavaScript.
Parentheses cannot be omitted as a condition, but the volume edges can be omitted on a single statement body.
Note that there is no type conversion from a non boolean type to a Boolean type, because in C and JavaScript, the IF (1) {...} Invalid solidity. return multiple values
When a function has multiple output parameters, return (V0, v1, ..., vn) can return multiple values. The number of components must be the same as the # of output parameters. Multiple values can be returned. The number of components must be the same as the number of output parameters. function Call Internal function Call
The function of the current contract can be called directly ("internally"), or it can be called recursively, as this meaningless example shows:
pragma solidity ^0.4.0;
Contract C {
function g (UINT a) returns (UINT ret) {return F ();}
function f () returns (UINT ret) {return G (7) + f ();}
}
These function calls are converted to simple jumps within the EVM. This has the effect that the current memory is not purged, and it is very effective to pass the memory reference to the interior called the function. The functionality of the same contract can only be invoked internally. External function Call
Expression THIS.G (8); and C.G (2); (where C is a contract instance) is also a valid function call, but this time, the function will be called "external", called by the message, rather than directly through the jump. Note that this is a function call that cannot be used in a constructor because the actual contract has not been created.
The functions of other contracts must be called externally. For an external invocation, all function arguments must be copied into memory.
You can use special options when invoking the functionality of another contract. Value () and. Gas () specifies the number of calls and gases sent together:
pragma solidity ^0.4.0;
Contract Infofeed {
function info () payable returns (UINT ret) {return;}
}
Contract Consumer {
infofeed feed;
function setfeed (address addr) {feed = Infofeed (addr);}
function Callfeed () {feed.info.value. Gas (i) ();}
}
Must be used for the payable of info, otherwise the. Value () option will not be available.
Note that the infofeed (addr) expression performs an explicit type conversion, which means "we know that the contract type for the given address is infofeed" and does not execute the constructor. An explicit type conversion must be handled with great care. Do not call, you do not know its type of contract function.
We can also directly use function Setfeed (infofeed _feed) {feed = _feed;}. Note Feed.info.value. Gas (800) only (local) sets the value and quantity of gas sent through a function call, with only the end brackets performing the actual call.
A function call causes an exception if the so-called contract does not (in this sense, the account does not contain code) exists, or if the contract itself is called to throw an exception or extinguish the gas.
Any interaction with another contract can create potential risks, especially if the source code for the contract is not known in advance. The current contract controls what is called a contract and may have an impact on anything. Even if the called contract inherits from a known parent contract, the inheritance contract only needs to have the correct interface. However, the execution of the contract can be entirely arbitrary and thus poses a danger. In addition, if you call another contract for your system before the first call returns, you should be prepared to even re-enter the call contract. This means that the called contract can change the status variable of the call contract by its function. Write your features, for example, calling an external function that occurs after any change to the state variable in your contract, your contract is not vulnerable to a reentrant vulnerability. named invocation and anonymous function parameters
Function call parameters can also be given in any order by name, if they are included in {}, and can be seen in the following example. The argument list must coincide with the list of parameters in the name and function declarations, but can be arranged in any order.
pragma solidity ^0.4.0;
Contract C {
function f (UINT key, uint value) {
//...
}
function g () {
//named arguments
F ({value:2, key:3});
}
omit function parameter name
You can omit the name of a parameter that is not used (especially the return parameter). These names still exist on the stack, but they are inaccessible.
pragma solidity ^0.4.0;
Contract C {
//omitted parameter name
function func (uint K, UINT) returns (UINT) {return
k;
}
}
Create a new contract
Contracts can create new contracts using the keyword new. The complete code for the contract being created must be known in advance, so it is not possible to create dependencies recursively.
pragma solidity ^0.4.0;
Contract D {
uint x;
function D (UINT a) payable {
x = A;
}
}
Contract C {
D d = new D (4);//will execute
function CreateD (uint arg) {
D newd = new D (ARG)
as part of the C constructor; function createandendowd (UINT arg, uint amount) {
//when created, send ether
d newd = (new D). Value (amount) (ARG);
}
As the example shows, you can use the. Value () option to forward ether to creation, but it is not possible to limit the amount of gas. If the creation fails (due to insufficient stack, insufficient balances, or other issues), an exception is thrown. evaluation Order of expressions
No evaluation order is specified for the expression (more formally, the order in which the child nodes of one node in the expression tree are evaluated is not specified, but is, of course, evaluated before the node itself). Only ensure that the statement is executed in order to complete the short circuit of the Boolean expression. For more information, see Operator Precedence. Assigning resolving allocations and returning multiple values
The internal solidity allows a tuple type, a list of potentially different types of objects at compile-time size. These tuples can be used to return multiple values at the same time and assign them to multiple variables (or general values) at the same time:
pragma solidity ^0.4.0;
Contract C {
uint[] data;
function f () returns (UINT, bool, uint) {return
(7, True, 2);
}
function g () {
//declare and assign variables. It is not possible to explicitly specify a type.
var (x, b, y) = f ();
Assigned to a pre-existing variable.
(x, y) = (2, 7);
Common techniques for exchanging values do not work for a value-less storage type.
(x, y) = (y, x);
components can be omitted (or can be used for variable declarations).
//If the tuple ends with an empty component, the remaining values are discarded.
(data.length,) = f ();//Set the length to 7
//The same thing can be done on the left.
(, data[3]) = f ();//Sets data[3] to 2
//component can only be excluded on the left side of the job, with one exception:
(x,) = (1,);
(1,) is the only way to specify a 1-tuple, because (1) is equal to 1.
}
}
complication arrays and structures
The semantics of assignment are somewhat complicated for non-numeric types, such as arrays and structs. assigning to a state variable always creates a separate copy. On the other hand, the local variable is assigned to create a separate copy of the base type, that is, for 32-byte static types. If a struct body or array (including bytes and strings) is assigned to a local variable from a state variable, the local variable holds a reference to the original state variable. The second assignment to the local variable does not modify the state, only the reference is changed. The allocation of a member (or element) of a local variable will change the state. scope definition and declaration
The declared variable will have the initial default value, and its byte representation is all zero. The "Default value" of a variable is a typical "0 state" of any type. For example, the default value for bool is false. The default value for the UINT or int type is 0. For statically sized arrays and bytes1 to BYTES32, each individual element is initialized to the default value corresponding to its type. Finally, for a dynamically sized array, byte and string, the default value is an empty array or a string.
A variable declared anywhere in a function will be within the scope of the entire function, regardless of where it is declared. This is because solidity inherits its scope rules from JavaScript. This contrasts with the many languages in which the scope is limited to variables to be declared until the semantic block ends. Therefore, the following code is illegal and causes the compiler to throw an error that the identifier has declared:
This does not compile
pragma solidity ^0.4.0;
Contract Scopingerrors {
function scoping () {
uint i = 0;
while (i++ < 1) {
uint same1 = 0;
}
while (i++ < 2) {
uint same1 = 0;//same1 Illegal, second declaration
}
}
function minimalscoping () {
UINT same2 = 0;
}
{
UINT same2 = 0;//same2 Illegal, second declaration
}
}
function forloopscoping () {for
(uint SAME3 = 0; ; 1; same3++) {
} for
(uint same3 = 0; same3 < 1; same3++) {//Same3 illegal, second declaration
}
}}
In addition, if a variable is declared, it will be initialized to its default value at the beginning of the function. Therefore, the following code is legal, albeit poorly written:
function foo () returns (UINT) {
//Baz is implicitly initialized to 0
uint bar = 5;
if (true) {
bar = = Baz
} else {
uint Baz = 10;//never perform
}
return bar;//returns 5
}
error Handling: Assert, Require, Revert and exceptions
Solidity uses state recovery exceptions to handle errors. This exception will undo all changes in the state of the current call (and all its child calls), and also flag the error to the caller. Convenient function assert and require can be used to check conditions and throw exceptions if the condition is not satisfied. The Assert function can only be used to test for internal errors and to check for invariants. You should use the Require function to ensure that valid conditions are met for an input or contract state variable, or to verify that a call from an external contract returns a value. If used correctly, the Profiling tools can evaluate your contract to identify the conditions and function calls that will reach the failure assertion. The normal running code should not reach the failed assertion declaration; If this happens, you will receive an error in your contract that you should fix.
There are two other ways to trigger an exception: the revert function can be used to mark an error and restore the current call. You may also be able to include details about the errors in the recovery call in the future. The Throw keyword can also be used as an alternative to revert ().
From version 0.4.13, the Throw keyword has been deprecated and will be eliminated in the future.
When exceptions occur in a child call, they are automatically "bubbling" (that is, the exception is rebooted). Exceptions to this rule are send and low-level function calls, delegate invocation and calling code-return false in exceptional cases instead of bubbling.
As part of the EVM design, if the calling account does not exist, the low-level call, the delegate call, and the calling code will return success. If necessary, you must check for existence before calling.
It is not possible to catch an exception.
In the following example, you can see how to use requirements to easily examine input conditions and how assertions are used for internal error checking:
pragma solidity ^0.4.0;
Contract Sharer {
function sendhalf (address addr) payable returns (UINT balance) {
require (msg.value% 2 = 0); Only even
uint Balancebeforetransfer = This.balance are allowed
; Addr.transfer (MSG.VALUE/2);
Because the transfer throws an exception failed and cannot be recalled here, we should have no way to still have half the money.
assert (This.balance = = BALANCEBEFORETRANSFER-MSG.VALUE/2);
Return this.balance
}
}
An assert style exception is generated in the following situations:
1. If you have large or negative index access to arrays (e.g. X[i] in I >= x.length or i < 0)
2. If you ethernet large or negative index access fixed length of bytesn.
3. If you divide or module to 0 (for example 5/0 or 23%0).
4. If by negative move amount.
5. If you convert a value of an enumerated type that is too large or negative.
6. If you call the 0 initialization variable of the intrinsic function type.
7. Call assert if you use an argument that evaluates to False.
Require-style exceptions are generated in the following situations:
1. Call Throw
2. Call require and the condition is false
3. If you call a function by using a message, it does not finish correctly (that is, it runs out of gas, does not have a matching function, or throws the exception itself) unless you use a low-level operation Call,send,delegatecall or Callcode. Lower-level operations do not throw an exception, but instead indicate failure by returning false.
4. If you use the New keyword, but the contract creation does not normally complete the Create contract (see the "Do not complete" definition above).
5. If you perform an external function call that directs a contract that does not contain code.
6. If your contract receives ether through a function-free modifier (including constructors and fallback functions) through public functions.
7. If your contract receives ether through a public getter function.
8. If. Transfer () fails.
Internally, solidity performs a restore operation (0XFD instruction) on the Require-style exception and performs an invalid operation (instruction 0xFE) to throw a Assert-style exception. In both cases, this causes EVM to revert to all changes made to the state. The reason for recovery is that there is no safe way to proceed because the expected effect is not occurring. Because we want to preserve the atomicity of the transaction, the safest approach is to recover all changes and invalidate the entire transaction (or at least the invocation). Note that the assertion-style exception consumes all the gas that is available in the invocation, and the requirement-style exception will not consume any gas that starts with the metropolis version.