# Cairo 之旅 III：通过 Starkling 学习 Felt 和 String

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

---

> 作者：[Darington Nnam](https://twitter.com/0xdarlington) 原文：[Journey through Cairo III — A deep dive into Strings and Felts with Starkling](https://medium.com/coinmonks/journey-through-cairo-iii-a-deep-dive-into-strings-and-felts-with-starklings-2bb6abff2d83) 翻译：[Louis Wang](https://twitter.com/lviswang) 校对：[「StarkNet 中文社区」](https://twitter.com/StarkNet_ZH)

欢迎来到我们 「Cairo 之旅」系列的第三课！在[上篇文章](https://mirror.xyz/starknet-zh.eth/MkxaRxBgs5BSW0jS7Plos4jIM2ZmRhUc5OEAzppBWKI)中，我们完成了 Starklings 语法部分的挑战，了解 Cairo 基本内容，包括命名空间 (Namespace)、结构体 (Struct) 等。今天我们将深入研究字符串 (Strings) 和整数 Felts。

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

Felts
-----

不像 Solidity 有相当多的各种数据类型，如 uints、strings、bools 等，Cairo 只有一个数据类型：felts。

Felts 代表字段元素。简单来说，它们是无符号的整数，最高精度 76 位小数。

虽然使用 felts 有很多优点，但我觉得它们也有一些恼人的缺点。比如说：

1\. 它们是一个 252 位的整数，当我们想把一个 uint256 的值放入其中时，就会出现问题。我们可以把 felts 组合成 tuples 来解决这个问题。

2\. 据 Cairo 的[官方文档](https://www.cairo-lang.org/docs/how_cairo_works/cairo_intro.html#field-elements)，在 Cairo 中，基本的数据类型是一个范围为 0≤x<P 的整数，其中 P 是一个素数（一般为 2^192+1）。这可能会给除法带来一些非常严重的问题，因为所有的除法运算 (x/y)，都必须满足这个条件：

    (x/y) * y == x
    

对于那些没有数学背景的人来说，上面的等式意味着，如果我们说 10 除以 5，其中 x=10，y=5，无论我们得到什么答案，当乘以 y（也就是5）时，必须返回 x（也就是10）。所以 10/5=2，而 2\*5=10。

但如果我们要做 10/3 呢？在其他 CPU 中，这应该是 3（忽略余数）或 3.333333333。但它不满足我们上面的方程式，所以 Cairo 这里的结果是一串奇怪的数字（实际上是2/(P+1)）。

为了解决这个问题，Cairo 有一个库，其中包含一组预写的 Cairo 代码，我们可以导入并直接在代码中使用。这些预写函数的一个例子是这里的 unsigned\_div\_rem，它可以用于安全除法，同时返回整数和除法后的剩余部分。

如果你想更深入地了解 Felts 是如何工作的，可以查看这里的[文档](https://www.cairo-lang.org/docs/how_cairo_works/cairo_intro.html#field-elements)。在了解 Felts 的一般功能后，让我们直接深入到字符串中去吧！

Strings
-------

虽然我们称它们为字符串 (Strings)，但 Cairo 目前一般不支持字符串。Cairo 支持的是我们称之为短字符串 (Short Strings) 的东西。

短字符串是指长度最多为 31 个字符的字符串，因此可以放入一个字段元素。虽然它们看起来像字符串，但它们在内部用 ASCII 码编码，因此可以用 felts 表示。

### 1\. strings00.cairo

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

这个练习会返回一系列的变量，我们要指定短字符串来通过这些变量测试。

为了通过这个测试我们只需复制粘贴测试中的短字符串：

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

成功通过！

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

但这样我们就会错过一些隐含的重要信息。我们更应该做的是创建一个 Python 脚本，将 felt 转换为字符串，将十六进制转换为字符串，这样我们就可以看到短字符串的生成。

为了完成这项工作，需要：

1\. 确保你的设备中安装了 python3。

2\. 创建一个名为 utils.py 的文件，并在其中粘贴下面的代码。

    MAX_LEN_FELT = 31
    
    def str_to_felt(text):
    if len(text) > MAX_LEN_FELT:
    raise Exception("Text length too long to convert to felt.")
    return int.from_bytes(text.encode(), "big")
    
    def felt_to_str(felt):
    length = (felt.bit_length() + 7) // 8
    return felt.to_bytes(length, byteorder="big").decode("utf-8")
    
    def str_to_felt_array(text):
    return [str_to_felt(text[i:i+MAX_LEN_FELT]) for i in range(0, len(text), MAX_LEN_FELT)]
    
    def uint256_to_int(uint256):
    return uint256[0] + uint256[1]*2**128
    
    def uint256(val):
    return (val & 2128-1, (val & (2256-2**128)) >> 128)
    
    def hex_to_felt(val):
    return int(val, 16)
    

打开终端运行以下命令：

    python3 -i utils.py
    

终端应该这样显示：

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

接着我们尝试将 felt 转换成短字符串：

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

下一步将十六进制数转换成字符串，不过需要先将十六进制转换成 felt，再转换成短字符串：

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

很好！这证明了短字符串只是编码的 ASCII，因此可以用等价的整数和十六进制数进行互换。

### 2. strings01.cairo

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

你知道短字符串可以进行数学运算吗？它们只是被编码的 ASCII 码，因此你可以用它们做任何你可以用整数做的事情，非常神奇！

现在让我们对短字符串做一些数学运算，传递给 **decode\_cipher1** 函数。

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

如果这看起来很奇怪，我希望你能忘记这些是短字符串，把它们当作数字就好，而且它也遵循四则运算：

    plaintext = ciphertext + key
    key = plaintext - ciphertext
    

已知 plaintext =‘Twinkle Twinkle Little Star’，那么：

    key = 'Twinkle Twinkle Little Star' - ciphertext
    

类似的在 decode\_cipher2 函数中，我们需要求解 ciphertext：

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

已知 plaintext = ‘**Magic Starknet Money’**，根据四则运算求解：

    plaintext = 1337 * ciphertext + 0xc0de
    ciphertext = (plaintext - 0xc0de) / 1337
    

OK！通过测试！

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

最后
--

恭喜你在成为 Cairo 专家的道路上取得了重大进展！你可以继续尝试 Starklings 教程的其他部分，期待我们的下一节课。

下篇文章，我们将学习数据存储。如果觉得本教程对你有帮助，转发分享给其他人吧~

---

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