# Cairo 之旅 V：隐式参数

By [Starknet 中文](https://paragraph.com/@starknet-zh) · 2022-10-28

---

> 作者：[Darington Nnam](https://twitter.com/0xdarlington) 原文：[Journey through Cairo V — Implict Arguments](https://medium.com/coinmonks/journey-through-cairo-v-implicit-arguments-fd8c3609b2) 翻译：[Louis Wang](https://twitter.com/lviswang) 校对：[「StarkNet 中文社区」](https://twitter.com/StarkNet_ZH)

欢迎来到我们的系列文章 「Cairo 之旅」第五讲。[上篇文章](https://mirror.xyz/starknet-zh.eth/6MUyx_DzjlJctp7S17RFvhZaQADvs3CJmVtzzHnC5mk)中，我们解释了 Cairo 中的存储，并仔细研究了如何使用 Cairo 的存储来实现映射。这一讲中我们将介绍隐式参数 (Implicit Arguments) 以及它们在 Cairo 中的作用。

像往常一样，如果你是中途加入的，建议从头开始看我们的文章。

_P.S：教程中的语法代码都是在 Cairo v0.9.0 版本下使用的_

隐式参数
----

Cairo 函数接受两种类型的参数：显性参数，在 `(`和`)` 之间提供；和隐性参数，在 `{`和`}` 之间提供。

两者之间的主要区别是，显性参数在函数主体内使用，不能在外部访问，而隐性参数能被其他调用它们的函数所继承。

让我们回顾[上篇存储文章](https://mirror.xyz/starknet-zh.eth/6MUyx_DzjlJctp7S17RFvhZaQADvs3CJmVtzzHnC5mk)中提及过的函数：

    @external
    func update_id{
          syscall_ptr : felt*,
          pedersen_ptr : HashBuiltin*,
          range_check_ptr
        }(_number: felt):
        id.write(_number)
    end
    

这个函数接收了三个隐含的参数：

1.  syscall\_ptr - 这个参数使 Cairo 函数能够被调用
    
2.  pedersen\_ptr - 这个参数用于计算 pedersen 哈希值
    
3.  range\_check\_ptr - 这个参数用于整数比较
    

你可能想知道，为什么我们需要传递所有这些参数？我们既没有计算任何哈希函数，甚至没有做任何整数比较。这是因为我们试图写入的存储变量需要这些隐含的参数，以便计算这个变量的实际内存地址。这在简单的变量中可能不需要，比如我们前面看的 `id` 存储变量，但是对于存储映射，比如 `balance`，计算 Pedersen hash 是 `read()` 和 `write()` 工作的一部分，这就是为什么调用这些存储变量的父函数必须明确说明这些隐式参数。

为了进一步理解这些，让我们深入到 Starklings 的练习中去吧！

implicit\_arguments01.cairo
---------------------------

![](https://storage.googleapis.com/papyrus_images/07f3485d15a68b8661b45f3549c7f37aca49f5cd57137f9ba98f317861783c7c.png)

这个练习要求我们修改 **implicit\_sum** 函数以使测试通过。从测试中我们可以看到，**test\_sum** 函数调用了 i**mplicit\_sum** 函数，向它隐式传递了参数 **a** 和 **b**。

为了使用这些参数，我们必须在 i**mplicit\_sum** 函数中也将它们指定为隐式参数，所以 Cairo 被告知这些参数可以或已经在函数调用之间传递。

    func implicit_sum{a: felt, b: felt}() -> (result: felt):
       return (a + b)
    end
    

![](https://storage.googleapis.com/papyrus_images/241d83d1f20377b1dbe59604f2d38d5e846e518be698961a0ea1f73e58ab553e.png)

在第 10 行里将参数修改进 {} 中就可以通过测试了

![](https://storage.googleapis.com/papyrus_images/492611b0ce442bf24283816b1ae0d02b64bb86a10bfc0c01d901865dbc7a0633.png)

implicit\_arguments02.cairo
---------------------------

![](https://storage.googleapis.com/papyrus_images/e8d451880881bf32827dfb53d0c32dd6b1fcfb33c24f362678e943e5277bb957.png)

在这个练习中，我们要修改 **child\_function\_1** 和 **child\_function\_2**，以使测试通过，但不能改变函数体。

父函数有两个隐式参数 a 和 b。child\_function\_1 使用隐式参数 a，child\_function\_2 使用隐式参数 b。我们要在函数构建中传入隐式参数。

对 **child\_function\_1：**

    func child_function_1{a: felt}() -> (result : felt):
       return (2 * a)
    end
    

对 child\_function\_2：

    func child_function_2{b: felt}() -> (result : felt):
    return (b + 3)
    end
    

![](https://storage.googleapis.com/papyrus_images/195effd9a2eb1e375951b22478dff47342d6c37b5e06e833c67641d64d0198d7.png)

顺利通过测试：）

![](https://storage.googleapis.com/papyrus_images/d6cb5dadfcc80dac8d5f36846f797abfa9f668b264fcc2ddc4664b43ac39b936.png)

implicit\_arguments03.cairo
---------------------------

![](https://storage.googleapis.com/papyrus_images/fcb31e82a2ea1a75ebb7ec48dff967858b553f5f4174ca3f99e314ffc6ffe9c0.png)

根据 Starklings 的说法，隐式参数的真正好处是它们会被任何使用它们的函数隐式返回，这是语言的一个非常强大的特性，因为它有助于可读性，让开发者在后续的函数调用中省略隐式参数。

在这个练习中，我们要修改 black\_box 函数以使测试通过。这一点非常容易做到，因为我们只需要将参数secret 分配给 `very secret!` 这句话，Cairo 就会自动返回这个参数，而不需要明确返回。

![](https://storage.googleapis.com/papyrus_images/f7033ed70fe2b52f724440d840c35decb647fc6d32c6deaed0c3e87f24e99eff.png)

轻松通过！

最后
--

我们已经完成 Cairo 之旅的一半，现在我相信你已经开始熟悉 Cairo 的工作方式了，从更广泛的角度来看。我们刚刚讨论了 Cairo 的隐式参数，以及它们在编写合约时对你有帮助。

如果觉得本教程对你有帮助，转发分享给其他人吧~

---

*Originally published on [Starknet 中文](https://paragraph.com/@starknet-zh/cairo-v)*
