mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #5755 from ethereum/docs-split-using-for
[DOCS] Split using for into new file
This commit is contained in:
commit
cfa1198892
@ -803,122 +803,4 @@ constant to be pushed onto the stack and the dispatcher
|
||||
code compares the current address against this constant
|
||||
for any non-view and non-pure function.
|
||||
|
||||
.. index:: ! using for, library
|
||||
|
||||
.. _using-for:
|
||||
|
||||
*********
|
||||
Using For
|
||||
*********
|
||||
|
||||
The directive ``using A for B;`` can be used to attach library
|
||||
functions (from the library ``A``) to any type (``B``).
|
||||
These functions will receive the object they are called on
|
||||
as their first parameter (like the ``self`` variable in Python).
|
||||
|
||||
The effect of ``using A for *;`` is that the functions from
|
||||
the library ``A`` are attached to *any* type.
|
||||
|
||||
In both situations, *all* functions in the library are attached,
|
||||
even those where the type of the first parameter does not
|
||||
match the type of the object. The type is checked at the
|
||||
point the function is called and function overload
|
||||
resolution is performed.
|
||||
|
||||
The ``using A for B;`` directive is active only within the current
|
||||
contract, including within all of its functions, and has no effect
|
||||
outside of the contract in which it is used. The directive
|
||||
may only be used inside a contract, not inside any of its functions.
|
||||
|
||||
By including a library, its data types including library functions are
|
||||
available without having to add further code.
|
||||
|
||||
Let us rewrite the set example from the
|
||||
:ref:`libraries` in this way::
|
||||
|
||||
pragma solidity >=0.4.16 <0.6.0;
|
||||
|
||||
// This is the same code as before, just without comments
|
||||
library Set {
|
||||
struct Data { mapping(uint => bool) flags; }
|
||||
|
||||
function insert(Data storage self, uint value)
|
||||
public
|
||||
returns (bool)
|
||||
{
|
||||
if (self.flags[value])
|
||||
return false; // already there
|
||||
self.flags[value] = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
function remove(Data storage self, uint value)
|
||||
public
|
||||
returns (bool)
|
||||
{
|
||||
if (!self.flags[value])
|
||||
return false; // not there
|
||||
self.flags[value] = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
function contains(Data storage self, uint value)
|
||||
public
|
||||
view
|
||||
returns (bool)
|
||||
{
|
||||
return self.flags[value];
|
||||
}
|
||||
}
|
||||
|
||||
contract C {
|
||||
using Set for Set.Data; // this is the crucial change
|
||||
Set.Data knownValues;
|
||||
|
||||
function register(uint value) public {
|
||||
// Here, all variables of type Set.Data have
|
||||
// corresponding member functions.
|
||||
// The following function call is identical to
|
||||
// `Set.insert(knownValues, value)`
|
||||
require(knownValues.insert(value));
|
||||
}
|
||||
}
|
||||
|
||||
It is also possible to extend elementary types in that way::
|
||||
|
||||
pragma solidity >=0.4.16 <0.6.0;
|
||||
|
||||
library Search {
|
||||
function indexOf(uint[] storage self, uint value)
|
||||
public
|
||||
view
|
||||
returns (uint)
|
||||
{
|
||||
for (uint i = 0; i < self.length; i++)
|
||||
if (self[i] == value) return i;
|
||||
return uint(-1);
|
||||
}
|
||||
}
|
||||
|
||||
contract C {
|
||||
using Search for uint[];
|
||||
uint[] data;
|
||||
|
||||
function append(uint value) public {
|
||||
data.push(value);
|
||||
}
|
||||
|
||||
function replace(uint _old, uint _new) public {
|
||||
// This performs the library function call
|
||||
uint index = data.indexOf(_old);
|
||||
if (index == uint(-1))
|
||||
data.push(_new);
|
||||
else
|
||||
data[index] = _new;
|
||||
}
|
||||
}
|
||||
|
||||
Note that all library calls are actual EVM function calls. This means that
|
||||
if you pass memory or value types, a copy will be performed, even of the
|
||||
``self`` variable. The only situation where no copy will be performed
|
||||
is when storage reference variables are used.
|
||||
.. include:: contracts/using-for.rst
|
119
docs/contracts/using-for.rst
Normal file
119
docs/contracts/using-for.rst
Normal file
@ -0,0 +1,119 @@
|
||||
.. index:: ! using for, library
|
||||
|
||||
.. _using-for:
|
||||
|
||||
*********
|
||||
Using For
|
||||
*********
|
||||
|
||||
The directive ``using A for B;`` can be used to attach library
|
||||
functions (from the library ``A``) to any type (``B``).
|
||||
These functions will receive the object they are called on
|
||||
as their first parameter (like the ``self`` variable in Python).
|
||||
|
||||
The effect of ``using A for *;`` is that the functions from
|
||||
the library ``A`` are attached to *any* type.
|
||||
|
||||
In both situations, *all* functions in the library are attached,
|
||||
even those where the type of the first parameter does not
|
||||
match the type of the object. The type is checked at the
|
||||
point the function is called and function overload
|
||||
resolution is performed.
|
||||
|
||||
The ``using A for B;`` directive is active only within the current
|
||||
contract, including within all of its functions, and has no effect
|
||||
outside of the contract in which it is used. The directive
|
||||
may only be used inside a contract, not inside any of its functions.
|
||||
|
||||
By including a library, its data types including library functions are
|
||||
available without having to add further code.
|
||||
|
||||
Let us rewrite the set example from the
|
||||
:ref:`libraries` in this way::
|
||||
|
||||
pragma solidity >=0.4.16 <0.6.0;
|
||||
|
||||
// This is the same code as before, just without comments
|
||||
library Set {
|
||||
struct Data { mapping(uint => bool) flags; }
|
||||
|
||||
function insert(Data storage self, uint value)
|
||||
public
|
||||
returns (bool)
|
||||
{
|
||||
if (self.flags[value])
|
||||
return false; // already there
|
||||
self.flags[value] = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
function remove(Data storage self, uint value)
|
||||
public
|
||||
returns (bool)
|
||||
{
|
||||
if (!self.flags[value])
|
||||
return false; // not there
|
||||
self.flags[value] = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
function contains(Data storage self, uint value)
|
||||
public
|
||||
view
|
||||
returns (bool)
|
||||
{
|
||||
return self.flags[value];
|
||||
}
|
||||
}
|
||||
|
||||
contract C {
|
||||
using Set for Set.Data; // this is the crucial change
|
||||
Set.Data knownValues;
|
||||
|
||||
function register(uint value) public {
|
||||
// Here, all variables of type Set.Data have
|
||||
// corresponding member functions.
|
||||
// The following function call is identical to
|
||||
// `Set.insert(knownValues, value)`
|
||||
require(knownValues.insert(value));
|
||||
}
|
||||
}
|
||||
|
||||
It is also possible to extend elementary types in that way::
|
||||
|
||||
pragma solidity >=0.4.16 <0.6.0;
|
||||
|
||||
library Search {
|
||||
function indexOf(uint[] storage self, uint value)
|
||||
public
|
||||
view
|
||||
returns (uint)
|
||||
{
|
||||
for (uint i = 0; i < self.length; i++)
|
||||
if (self[i] == value) return i;
|
||||
return uint(-1);
|
||||
}
|
||||
}
|
||||
|
||||
contract C {
|
||||
using Search for uint[];
|
||||
uint[] data;
|
||||
|
||||
function append(uint value) public {
|
||||
data.push(value);
|
||||
}
|
||||
|
||||
function replace(uint _old, uint _new) public {
|
||||
// This performs the library function call
|
||||
uint index = data.indexOf(_old);
|
||||
if (index == uint(-1))
|
||||
data.push(_new);
|
||||
else
|
||||
data[index] = _new;
|
||||
}
|
||||
}
|
||||
|
||||
Note that all library calls are actual EVM function calls. This means that
|
||||
if you pass memory or value types, a copy will be performed, even of the
|
||||
``self`` variable. The only situation where no copy will be performed
|
||||
is when storage reference variables are used.
|
Loading…
Reference in New Issue
Block a user