mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			120 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
			
		
		
	
	
			120 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
.. 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.7.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.7.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.
 |