哪些是你会提醒其它开发者的? 哪些是是在其他语言里可行,而Solidity不可行的? 比如说:什么参数可以被传入函数,什么参数可以从函数返回?

原文地址

6 人回答 0

6 个回答
投票数
最旧发布
最近发布

回答发布于 2018-09-03 15:19:41

string[]不允许作为函数参数或返回值。 参考这里的讨论: Is it impossible to use an array of strings as the argument to solidity function?

||
||

回答发布于 2018-09-03 15:18:21

声明一个局部数组(或其它引用类型) 并且假设它会在memory中创建而实际上写到了storage:

/// THIS CONTRACT CONTAINS AN ERROR
contract C {
    uint someVariable;
    uint[] data;

    function f() {
        uint[] x;
        x.push(2);
        data = x;
    }
}

局部变量x的类型是uint[] storage,但是由于storage不是动态分配的,在使用前需要用一个状态变量赋值。所以x没有在storage中分配空间。它的作用相当于在storage中已经存在的变量的别名。

会发生的是编译器将x译作一个storage指针,并且默认让它指向storage slot 0。这导致某个变量(存放在storage slot 0)被x.push(2)改变。正确的方法是:

contract C {
    uint someVariable;
    uint[] data;

    function f() {
        uint[] x = data;
        x.push(2);
    }
}

OR

contract C {
    uint someVariable;
    uint[] data;

    function f() {
        uint[] memory x = new uint[](1);
        x[0] = 2;
        data = x;
    }
}
||
||

回答发布于 2018-09-03 15:18:20

从这篇文档

在 for(var i=0;i<arrayName.length;i++){...},i的类型会是uint8,因为这是可以包含0的最小类型。如果数组有多于255个元素,循环不会终止。

另外

目前不可能在external函数中使用数组的数组。。。你仅能够用1级 动态数组。

并且

由于EVM的限制,不可能external函数调用中返回动态内容。在contract{function f() returns (uint[]){....}}中 函数f如果从web3.js调用会返回某些值,但是从Solidity调用不会。目前的变通方案是使用大的静态数组。

||
||

回答发布于 2018-09-03 15:18:19
  • 总是为一个交易提供足够的gas(90%的低级bug都是因为没有足够的gas)
  • 异常会消耗所有的交易gas(谨慎使用)
  • 无法简单验证你的合约是否抛出一个异常
  • 无法简单核对你的交易是否用尽gas
  • 在testnet上也许能工作,但是可能在私有testnet上失败(核对是否在两者上都能工作)
  • 没有外部库的话,只有对string的有限支持
  • 一些函数可能失败(比如send),核对返回值
  • 当心重入问题(特别是发送钱或其它类型token)
||
||

回答发布于 2018-09-03 15:18:16

returns使用命名输出变量会引入新的局部变量。

比如从这个问题

contract Test {
    address owner;

    function Test(){
        owner = msg.sender;
    }

    function getOwner() returns (address owner) {
        return owner;
    }
}

这里在getOwner,新的变量owner被引入了并且被初始化为0。它碰巧覆盖了状态变量owner,导致了非预期的结果。

Mappings仅允许状态变量(或者说在函数内部的storage类型)。

比如从这个问题:

function getBalance(address addr) returns (uint, uint) {
    mapping(address => uint)  balancers;
    balancers[msg.sender] = 500;

    return (balancesA[addr], balancesB[addr]);
}

这里mapping(address => uint) balances 没有分配新的mapping但引入了未初始化的变量。因此访问balancers[msg.sender]是不合法的。

||
||

回答发布于 2018-09-03 15:18:15
  • 在数组中使用delete会产生一个间隔,所以你需要手动地去移动数组元素并且更新数组的length属性
  • stringbytes一样,但是不允许length和索引访问。
  • bytesbyte[]一样,byte[]每个元素所占空间更多,后者代价更高。
  • Date后缀不能用于变量。
  • Solidity从Javascript继承了作用域规则;没有块作用域。

关于更多solidity gotchas, https://github.com/miguelmota/solidity-idiosyncrasies

||
||

回答发布于 2018-09-03 15:18:15
  • 在数组中使用delete会产生一个间隔,所以你需要手动地去移动数组元素并且更新数组的length属性
  • stringbytes一样,但是不允许length和索引访问。
  • bytesbyte[]一样,byte[]每个元素所占空间更多,后者代价更高。
  • Date后缀不能用于变量。
  • Solidity从Javascript继承了作用域规则;没有块作用域。

关于更多solidity gotchas, https://github.com/miguelmota/solidity-idiosyncrasies

||
||

回答发布于 2018-09-03 15:18:16

returns使用命名输出变量会引入新的局部变量。

比如从这个问题

contract Test {
    address owner;

    function Test(){
        owner = msg.sender;
    }

    function getOwner() returns (address owner) {
        return owner;
    }
}

这里在getOwner,新的变量owner被引入了并且被初始化为0。它碰巧覆盖了状态变量owner,导致了非预期的结果。

Mappings仅允许状态变量(或者说在函数内部的storage类型)。

比如从这个问题:

function getBalance(address addr) returns (uint, uint) {
    mapping(address => uint)  balancers;
    balancers[msg.sender] = 500;

    return (balancesA[addr], balancesB[addr]);
}

这里mapping(address => uint) balances 没有分配新的mapping但引入了未初始化的变量。因此访问balancers[msg.sender]是不合法的。

||
||

回答发布于 2018-09-03 15:18:19
  • 总是为一个交易提供足够的gas(90%的低级bug都是因为没有足够的gas)
  • 异常会消耗所有的交易gas(谨慎使用)
  • 无法简单验证你的合约是否抛出一个异常
  • 无法简单核对你的交易是否用尽gas
  • 在testnet上也许能工作,但是可能在私有testnet上失败(核对是否在两者上都能工作)
  • 没有外部库的话,只有对string的有限支持
  • 一些函数可能失败(比如send),核对返回值
  • 当心重入问题(特别是发送钱或其它类型token)
||
||

回答发布于 2018-09-03 15:18:20

从这篇文档

在 for(var i=0;i<arrayName.length;i++){...},i的类型会是uint8,因为这是可以包含0的最小类型。如果数组有多于255个元素,循环不会终止。

另外

目前不可能在external函数中使用数组的数组。。。你仅能够用1级 动态数组。

并且

由于EVM的限制,不可能external函数调用中返回动态内容。在contract{function f() returns (uint[]){....}}中 函数f如果从web3.js调用会返回某些值,但是从Solidity调用不会。目前的变通方案是使用大的静态数组。

||
||

回答发布于 2018-09-03 15:18:21

声明一个局部数组(或其它引用类型) 并且假设它会在memory中创建而实际上写到了storage:

/// THIS CONTRACT CONTAINS AN ERROR
contract C {
    uint someVariable;
    uint[] data;

    function f() {
        uint[] x;
        x.push(2);
        data = x;
    }
}

局部变量x的类型是uint[] storage,但是由于storage不是动态分配的,在使用前需要用一个状态变量赋值。所以x没有在storage中分配空间。它的作用相当于在storage中已经存在的变量的别名。

会发生的是编译器将x译作一个storage指针,并且默认让它指向storage slot 0。这导致某个变量(存放在storage slot 0)被x.push(2)改变。正确的方法是:

contract C {
    uint someVariable;
    uint[] data;

    function f() {
        uint[] x = data;
        x.push(2);
    }
}

OR

contract C {
    uint someVariable;
    uint[] data;

    function f() {
        uint[] memory x = new uint[](1);
        x[0] = 2;
        data = x;
    }
}
||
||

回答发布于 2018-09-03 15:19:41

string[]不允许作为函数参数或返回值。 参考这里的讨论: Is it impossible to use an array of strings as the argument to solidity function?

||
||

回答发布于 2018-09-03 15:19:41

string[]不允许作为函数参数或返回值。 参考这里的讨论: Is it impossible to use an array of strings as the argument to solidity function?

||
||

回答发布于 2018-09-03 15:18:21

声明一个局部数组(或其它引用类型) 并且假设它会在memory中创建而实际上写到了storage:

/// THIS CONTRACT CONTAINS AN ERROR
contract C {
    uint someVariable;
    uint[] data;

    function f() {
        uint[] x;
        x.push(2);
        data = x;
    }
}

局部变量x的类型是uint[] storage,但是由于storage不是动态分配的,在使用前需要用一个状态变量赋值。所以x没有在storage中分配空间。它的作用相当于在storage中已经存在的变量的别名。

会发生的是编译器将x译作一个storage指针,并且默认让它指向storage slot 0。这导致某个变量(存放在storage slot 0)被x.push(2)改变。正确的方法是:

contract C {
    uint someVariable;
    uint[] data;

    function f() {
        uint[] x = data;
        x.push(2);
    }
}

OR

contract C {
    uint someVariable;
    uint[] data;

    function f() {
        uint[] memory x = new uint[](1);
        x[0] = 2;
        data = x;
    }
}
||
||

回答发布于 2018-09-03 15:18:20

从这篇文档

在 for(var i=0;i<arrayName.length;i++){...},i的类型会是uint8,因为这是可以包含0的最小类型。如果数组有多于255个元素,循环不会终止。

另外

目前不可能在external函数中使用数组的数组。。。你仅能够用1级 动态数组。

并且

由于EVM的限制,不可能external函数调用中返回动态内容。在contract{function f() returns (uint[]){....}}中 函数f如果从web3.js调用会返回某些值,但是从Solidity调用不会。目前的变通方案是使用大的静态数组。

||
||

回答发布于 2018-09-03 15:18:19
  • 总是为一个交易提供足够的gas(90%的低级bug都是因为没有足够的gas)
  • 异常会消耗所有的交易gas(谨慎使用)
  • 无法简单验证你的合约是否抛出一个异常
  • 无法简单核对你的交易是否用尽gas
  • 在testnet上也许能工作,但是可能在私有testnet上失败(核对是否在两者上都能工作)
  • 没有外部库的话,只有对string的有限支持
  • 一些函数可能失败(比如send),核对返回值
  • 当心重入问题(特别是发送钱或其它类型token)
||
||

回答发布于 2018-09-03 15:18:16

returns使用命名输出变量会引入新的局部变量。

比如从这个问题

contract Test {
    address owner;

    function Test(){
        owner = msg.sender;
    }

    function getOwner() returns (address owner) {
        return owner;
    }
}

这里在getOwner,新的变量owner被引入了并且被初始化为0。它碰巧覆盖了状态变量owner,导致了非预期的结果。

Mappings仅允许状态变量(或者说在函数内部的storage类型)。

比如从这个问题:

function getBalance(address addr) returns (uint, uint) {
    mapping(address => uint)  balancers;
    balancers[msg.sender] = 500;

    return (balancesA[addr], balancesB[addr]);
}

这里mapping(address => uint) balances 没有分配新的mapping但引入了未初始化的变量。因此访问balancers[msg.sender]是不合法的。

||
||

回答发布于 2018-09-03 15:18:15
  • 在数组中使用delete会产生一个间隔,所以你需要手动地去移动数组元素并且更新数组的length属性
  • stringbytes一样,但是不允许length和索引访问。
  • bytesbyte[]一样,byte[]每个元素所占空间更多,后者代价更高。
  • Date后缀不能用于变量。
  • Solidity从Javascript继承了作用域规则;没有块作用域。

关于更多solidity gotchas, https://github.com/miguelmota/solidity-idiosyncrasies

||
||