Functions
Constant size values stored on the stack or in memory can be passed into and returned by functions.
Syntax
Function :
FunctionQualifiersfn
IDENTIFIER
(
FunctionParameters?)
FunctionReturnType?
{
FunctionStatements*
}
FunctionQualifiers :
pub
?FunctionStatements :
ReturnStatement
| VariableDeclarationStatement
| AssignStatement
| AugmentedAssignStatement
| ForStatement
| WhileStatement
| IfStatement
| AssertStatement
| BreakStatement
| ContinueStatement
| RevertStatement
| ExpressionFunctionParameters :
self
? |self,
? FunctionParam (,
FunctionParam)*,
?FunctionParam :
FunctionParamLabel? IDENTIFIER:
TypesFunctionParamLabel :
_ | IDENTIFIERFunctionReturnType :
->
Types
A function definition consists of name and code block along with an optional
list of parameters and return value. Functions are declared with the
keyword fn
. Functions may declare a set of input parameters,
through which the caller passes arguments into the function, and
the output type of the value the function will return to its caller
on completion.
When referred to, a function yields a first-class value of the corresponding zero-sized function type, which when called evaluates to a direct call to the function.
A function header prepends a set or curly brackets {...}
which contain the function body.
For example, this is a simple function:
fn add(x: u256, y: u256) -> u256 {
return x + y
}
Functions can be defined inside of a contract, inside of a struct, or at the "top level" of a module (that is, not nested within another item).
Example:
fn add(_ x: u256, _ y: u256) -> u256 {
return x + y
}
contract CoolCoin {
balance: Map<address, u256>
fn transfer(mut self, from sender: address, to recipient: address, value: u256) -> bool {
if self.balance[sender] < value {
return false
}
self.balance[sender] -= value
self.balance[recipient] += value
return true
}
pub fn demo(mut self) {
let ann: address = 0xaa
let bob: address = 0xbb
self.balance[ann] = 100
let bonus: u256 = 2
let value: u256 = add(10, bonus)
let ok: bool = self.transfer(from: ann, to: bob, value)
}
}
Function parameters have optional labels. When a function is called, the arguments must be labeled and provided in the order specified in the function definition.
The label of a parameter defaults to the parameter name; a different label can be specified by adding an explicit label prior to the parameter name. For example:
fn encrypt(msg cleartext: u256, key: u256) -> u256 {
return cleartext ^ key
}
fn demo() {
let out: u256 = encrypt(msg: 0xdecafbad, key: 0xfefefefe)
}
Here, the first parameter of the encrypt
function has the label msg
,
which is used when calling the function, while the parameter name is
cleartext
, which is used inside the function body. The parameter name
is an implementation detail of the function, and can be changed without
modifying any function calls, as long as the label remains the same.
When calling a function, a label can be omitted when the argument is a variable with a name that matches the parameter label. Example:
let msg: u256 = 0xdecafbad
let cyf: u256 = encrypt(msg, key: 0x1234)
A parameter can also be specified to have no label, by using _
in place of a
label in the function definition. In this case, when calling the function, the
corresponding argument must not be labeled. Example:
fn add(_ x: u256, _ y: u256) -> u256 {
return x + y
}
fn demo() {
let sum: u256 = add(16, 32)
}
Functions defined inside of a contract or struct may take self
as a
parameter. This gives the function the ability to read and write contract
storage or struct fields, respectively. If a function takes self
as a parameter, the function must be called via self
. For example:
let ok: bool = self.transfer(from, to, value)
self
is expected to come first parameter in the function's parameter list.
Functions can also take a Context
object which gives access to EVM features that read or write
blockchain and transaction data. Context
is expected to be first in the function's parameter list
unless the function takes self
, in which case Context
should come second.