Truffle 字符串指南

Truffle 字符串是 Truffle 的基本字符串类型,可以在语言之间共享。鼓励语言实现者使用 Truffle 字符串作为其语言的字符串类型,以实现更轻松的互操作性和更高的性能。

TruffleString 支持多种字符串编码,但专门针对最常用的编码进行了优化

  • UTF-8
  • UTF-16
  • UTF-32
  • US-ASCII
  • ISO-8859-1
  • BYTES

TruffleString API #

TruffleString 公开的所有操作都作为内部 Node 提供,以及作为静态或实例方法提供。用户应尽可能使用提供的节点,因为静态/实例方法只是执行其各自节点的未缓存版本的简写。所有节点都命名为 {NameOfOperation}Node,所有便捷方法都命名为 {nameOfOperation}Uncached

某些操作支持延迟计算,例如延迟连接或某些字符串属性的延迟计算。大多数这些操作都提供一个参数 boolean lazy,允许用户在每个调用点处启用或禁用延迟计算。

处理索引值的操作(例如 CodePointAtIndex)有两种变体:基于代码点的索引和基于字节的索引。基于字节的索引由操作名称中的 ByteIndex 后缀或前缀指示,否则索引基于代码点。例如,CodePointAtIndex 的索引参数是基于代码点的,而 CodePointAtByteIndex 使用基于字节的索引。

目前可用的操作列表如下,并按类别分组。

创建新的 TruffleString

  • FromCodePoint: 从给定的代码点创建一个新的 TruffleString。
  • FromLong: 从给定的长整型值创建一个新的 TruffleString。
  • FromByteArray: 从给定的字节数组创建一个新的 TruffleString。
  • FromCharArrayUTF16: 从给定的字符数组创建一个 UTF-16 TruffleString。
  • FromIntArrayUTF32: 从给定的整数数组创建一个 UTF-32 TruffleString。
  • FromJavaString: 从给定的 java.lang.String 创建一个 TruffleString。
  • FromNativePointer: 从给定的本机指针创建一个新的 TruffleString。
  • Encoding#getEmpty: 获取该编码中的空 TruffleString。

查询字符串属性

  • isEmpty: 检查字符串是否为空。
  • CodePointLength: 获取字符串的代码点长度。
  • byteLength: 获取字符串的字节长度。
  • IsValid: 检查字符串是否编码正确。
  • GetCodeRange: 获取有关字符串内容的粗略信息(字符串中的所有代码点是否都在 ASCII/LATIN-1/BMP 范围内?)。
  • GetByteCodeRange: 获取有关字符串内容的粗略信息,不考虑 16/32 位编码。
  • CodeRangeEquals: 检查字符串的代码范围是否等于给定的代码范围。
  • isCompatibleTo: 检查字符串是否与给定编码兼容/可以在给定编码中查看。
  • isManaged: 检查字符串是否未由本机指针支持。
  • isNative: 检查字符串是否由本机指针支持。
  • isImmutable: 检查字符串是否为 TruffleString 的实例。
  • isMutable: 检查字符串是否为 MutableTruffleString 的实例。

比较

  • Equal: 检查两个字符串是否相等。请注意,此操作对编码敏感!
  • RegionEqual: 检查两个字符串在由基于代码点的偏移量和长度定义的给定区域中是否相等。
  • RegionEqualByteIndex: 检查两个字符串在由基于字节的偏移量和长度定义的给定区域中是否相等。
  • CompareBytes: 字节比较两个字符串。
  • CompareCharsUTF16: 字符比较两个 UTF-16 字符串。
  • CompareIntsUTF32: 整数比较两个 UTF-32 字符串。
  • HashCode: 获取字符串的哈希码。哈希码基于字符串的字节,因此具有相同代码点但编码不同的字符串可能具有不同的哈希码。

转换

  • SwitchEncoding: 将字符串转换为给定编码。
  • ForceEncoding: 创建一个字符串,该字符串包含与给定字符串相同的字节,但分配给给定的编码。
  • AsTruffleString: 将 MutableTruffleString 转换为不可变的 TruffleString。
  • AsManaged: 将由本机指针支持的 TruffleString 转换为由 Java 字节数组支持的 TruffleString。
  • ToValidString: 将 TruffleString 转换为编码正确的版本。
  • CopyToByteArray: 将字符串的内容复制到字节数组中。
  • GetInternalByteArray: 获取字符串的内部字节数组。
  • CopyToNativeMemory: 将字符串的内容复制到本机指针中。
  • GetInternalNativePointer: 获取本机字符串的指针对象。
  • ToJavaString: 将字符串转换为 java.lang.String
  • ParseInt: 将字符串的内容解析为整数。
  • ParseLong: 将字符串的内容解析为长整型。
  • ParseDouble: 将字符串的内容解析为双精度浮点型。

访问代码点和字节

搜索

  • ByteIndexOfAnyByte: 查找字符串中一组给定字节的第一次出现并返回其基于字节的索引。
  • CharIndexOfAnyCharUTF16: 查找 UTF-16 字符串中一组给定字符的第一次出现并返回其基于字符的索引。
  • IntIndexOfAnyIntUTF32: 查找 UTF-32 字符串中一组给定整数的第一次出现并返回其基于整数的索引。
  • IndexOfCodePoint: 查找字符串中给定代码点的第一次出现并返回其基于代码点的索引。
  • ByteIndexOfCodePoint: 在字符串中查找给定码点的第一个出现位置,并返回其基于字节的索引。
  • ByteIndexOfCodePointSet: 在字符串中查找给定集合中包含的第一个码点的出现位置,并返回其基于字节的索引。
  • LastIndexOfCodePoint: 在字符串中查找给定码点的最后一个出现位置,并返回其基于码点的索引。
  • LastByteIndexOfCodePoint: 在字符串中查找给定码点的最后一个出现位置,并返回其基于字节的索引。
  • IndexOfString: 在字符串中查找给定子字符串的第一个出现位置,并返回其基于码点的索引。
  • ByteIndexOfString: 在字符串中查找给定子字符串的第一个出现位置,并返回其基于字节的索引。
  • LastIndexOfString: 在字符串中查找给定子字符串的最后一个出现位置,并返回其基于码点的索引。
  • LastByteIndexOfString: 在字符串中查找给定子字符串的最后一个出现位置,并返回其基于字节的索引。

组合

  • Concat: 连接两个字符串。
  • Substring: 从给定字符串中创建一个子字符串,由基于码点的偏移量和长度限定。
  • SubstringByteIndex: 从给定字符串中创建一个子字符串,由基于字节的偏移量和长度限定。
  • Repeat: 将给定字符串重复n次。

实例化 #

可以从码点、数字、基本类型数组或 java.lang.String 创建 TruffleString

可以使用 TruffleString.FromByteArrayNode 创建任何编码的字符串,它期望一个包含已编码字符串的字节数组。通过将 copy 参数设置为 false,此操作可以是非复制的。

重要:TruffleStrings 将假定数组内容是不可变的,在将数组传递给此操作的非复制变体后,不要修改数组。

import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.strings.TruffleString;

abstract static class SomeNode extends Node {

    @Specialization
    static TruffleString someSpecialization(
            @Cached TruffleString.FromByteArrayNode fromByteArrayNode) {
        byte[] array = {'a', 'b', 'c'};
        return fromByteArrayNode.execute(array, 0, array.length, TruffleString.Encoding.UTF_8, false);
    }
}

为了更轻松地创建与系统字节序无关的 UTF-16 和 UTF-32 字符串,TruffleString 提供了 TruffleString.FromCharArrayUTF16NodeTruffleString.FromIntArrayUTF32Node

也可以通过 TruffleStringBuilder 创建 TruffleString,它是 TruffleString 等效于 java.lang.StringBuilder 的类。

TruffleStringBuilder 提供以下操作

  • AppendByte: 将单个字节追加到字符串生成器。
  • AppendCharUTF16: 将单个字符追加到 UTF-16 字符串生成器。
  • AppendCodePoint: 将单个码点追加到字符串生成器。
  • AppendIntNumber: 将整数追加到字符串生成器。
  • AppendLongNumber: 将长整数追加到字符串生成器。
  • AppendString: 将 TruffleString 追加到字符串生成器。
  • AppendSubstringByteIndex: 将由基于字节的偏移量和长度定义的子字符串追加到字符串生成器。
  • AppendJavaStringUTF16: 将由基于字符的偏移量和长度定义的 Java 字符串子字符串追加到字符串生成器。
  • ToString: 从字符串生成器创建新的 TruffleString。

参见以下示例

import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.strings.TruffleString;
import com.oracle.truffle.api.strings.TruffleStringBuilder;

abstract static class SomeNode extends Node {

    @Specialization
    static TruffleString someSpecialization(
            @Cached TruffleStringBuilder.AppendCharUTF16Node appendCharNode,
            @Cached TruffleStringBuilder.AppendJavaStringUTF16Node appendJavaStringNode,
            @Cached TruffleStringBuilder.AppendIntNumberNode appendIntNumberNode,
            @Cached TruffleStringBuilder.AppendStringNode appendStringNode,
            @Cached TruffleString.FromCharArrayUTF16Node fromCharArrayUTF16Node,
            @Cached TruffleStringBuilder.AppendCodePointNode appendCodePointNode,
            @Cached TruffleStringBuilder.ToStringNode toStringNode) {
        TruffleStringBuilder sb = TruffleStringBuilder.create(TruffleString.Encoding.UTF_16);
        sb = appendCharNode.execute(sb, 'a');
        sb = appendJavaStringNode.execute(sb, "abc", /* fromIndex: */ 1, /* length: */ 2);
        sb = appendIntNumberNode.execute(sb, 123);
        TruffleString string = fromCharArrayUTF16Node.execute(new char[]{'x', 'y'}, /* fromIndex: */ 0, /* length: */ 2);
        sb = appendStringNode.execute(sb, string);
        sb = appendCodePointNode.execute(sb, 'z');
        return toStringNode.execute(sb); // string content: "abc123xyz"
    }
}

编码 #

每个 TruffleString 都以特定内部编码进行编码,该编码在实例化期间设置。

TruffleString 针对以下编码进行了完全优化

  • UTF-8
  • UTF-16
  • UTF-32
  • US-ASCII
  • ISO-8859-1
  • BYTES

支持许多其他编码,但没有完全优化。要使用它们,必须通过在 Truffle 语言注册 中设置 needsAllEncodings = true 来启用它们。

不公开 TruffleString 的内部编码。语言不应该查询字符串的编码,而应该在字符串编码有影响的方法(几乎所有操作)中传递 expectedEncoding 参数。这允许在编码之间转换时重用字符串对象,如果字符串在两种编码中都是字节等效的。可以使用 SwitchEncodingNode 将字符串转换为不同的编码,如下例所示

import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.strings.TruffleString;
import com.oracle.truffle.api.strings.TruffleStringBuilder;

abstract static class SomeNode extends Node {

    @Specialization
    static void someSpecialization(
            @Cached TruffleString.FromJavaStringNode fromJavaStringNode,
            @Cached TruffleString.ReadByteNode readByteNode,
            @Cached TruffleString.SwitchEncodingNode switchEncodingNode,
            @Cached TruffleString.ReadByteNode utf8ReadByteNode) {

        // instantiate a new UTF-16 string
        TruffleString utf16String = fromJavaStringNode.execute("foo", TruffleString.Encoding.UTF_16);

        // read a byte with expectedEncoding = UTF-16.
        // if the string is not byte-compatible with UTF-16, this method will throw an IllegalArgumentException
        System.out.printf("%x%n", readByteNode.execute(utf16String, /* byteIndex */ 0, TruffleString.Encoding.UTF_16));

        // convert to UTF-8.
        // note that utf8String may be reference-equal to utf16String!
        TruffleString utf8String = switchEncodingNode.execute(utf16String, TruffleString.Encoding.UTF_8);

        // read a byte with expectedEncoding = UTF-8
        // if the string is not byte-compatible with UTF-8, this method will throw an IllegalArgumentException
        System.out.printf("%x%n", utf8ReadByteNode.execute(utf8String, /* byteIndex */ 0, TruffleString.Encoding.UTF_8));
    }
}

在 UTF-16 和 UTF-32 上进行字符串压缩后,确定编码之间的字节等效性,因此例如压缩的 UTF-16 字符串与 ISO-8859-1 字节等效,并且如果其所有字符都在 ASCII 范围内(参见 CodeRange),它也与 UTF-8 字节等效。

要检查您的代码是否正确切换编码,请使用系统属性 truffle.strings.debug-strict-encoding-checks=true 运行您的单元测试。这会在切换编码时禁用字符串对象的重用,并使编码检查更严格:在单个字符串上进行的所有操作都将强制执行精确匹配,而对两个字符串进行的操作仍然允许字节等效的重新解释。

所有具有两个以上字符串参数的 TruffleString 操作都需要字符串以与结果编码兼容的编码进行编码。因此,字符串需要使用相同的编码,或者调用者必须确保两个字符串都与结果编码 兼容。这使已经知道 SwitchEncodingNodes 是空操作的调用者能够出于占用空间的原因而跳过它们。

import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.strings.TruffleString;
import com.oracle.truffle.api.strings.TruffleStringBuilder;

abstract static class SomeNode extends Node {

    @Specialization
    static boolean someSpecialization(
            TruffleString a,
            TruffleString b,
            @Cached TruffleString.SwitchEncodingNode switchEncodingNodeA,
            @Cached TruffleString.SwitchEncodingNode switchEncodingNodeB,
            @Cached TruffleString.EqualNode equalNode) {
        TruffleString utf8A = switchEncodingNodeA.execute(a, TruffleString.Encoding.UTF_8);
        TruffleString utf8B = switchEncodingNodeB.execute(b, TruffleString.Encoding.UTF_8);
        return equalNode.execute(utf8A, utf8B, TruffleString.Encoding.UTF_8);
    }
}

字符串属性 #

TruffleString 公开了以下属性

  • byteLength:字符串的字节长度,通过 byteLength 方法公开。
  • codePointLength:字符串的码点长度,通过 CodePointLengthNode 公开。
  • isValid:可以通过 IsValidNode 查询,以检查字符串是否正确编码。
  • codeRange:提供有关字符串内容的粗略信息,通过 GetCodeRangeNode 公开。此属性可以具有以下值
    • ASCII:此字符串中的所有码点都是基本拉丁 Unicode 块的一部分,也称为 ASCII(0x00 - 0x7f)。
    • LATIN-1:此字符串中的所有码点都是 ISO-8859-1 字符集的一部分(0x00 - 0xff),它等效于基本拉丁和拉丁-1 补充 Unicode 块的并集。字符串中的至少一个码点大于 0x7f。仅适用于 ISO-8859-1、UTF-16 和 UTF-32。
    • BMP:此字符串中的所有码点都是 Unicode 基本多语言平面 (BMP) 的一部分(0x0000 - 0xffff)。字符串中的至少一个码点大于 0xff。仅适用于 UTF-16 和 UTF-32。
    • VALID:此字符串已正确编码,并且包含至少一个不在其他适用代码范围内(例如,对于 UTF-8,这意味着有一个码点不在 ASCII 范围内,而对于 UTF-16,这意味着有一个码点不在 BMP 范围内)的码点。
    • BROKEN:此字符串未正确编码。无法确定有关其内容的更多信息。
  • hashCode:字符串的哈希码,通过 HashCodeNode 公开。哈希码取决于字符串的编码;在比较哈希码之前,字符串必须始终转换为通用编码!

参见以下示例,说明如何查询 TruffleString 公开的属性

import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.strings.TruffleString;

abstract static class SomeNode extends Node {

    @Specialization
    static TruffleString someSpecialization(
            TruffleString string,
            @Cached TruffleString.CodePointLengthNode codePointLengthNode,
            @Cached TruffleString.IsValidNode isValidNode,
            @Cached TruffleString.GetCodeRangeNode getCodeRangeNode,
            @Cached TruffleString.HashCodeNode hashCodeNode) {
        System.out.println("byte length: " + string.byteLength(TruffleString.Encoding.UTF_8));
        System.out.println("codepoint length: " + codePointLengthNode.execute(string, TruffleString.Encoding.UTF_8));
        System.out.println("is valid: " + isValidNode.execute(string));
        System.out.println("code range: " + getCodeRangeNode.execute(string));
        System.out.println("hash code: " + hashCodeNode.execute(string, TruffleString.Encoding.UTF_8));
    }
}

字符串相等性和比较 #

应使用 EqualNode 检查 TruffleString 对象是否相等。与 HashCodeNode 一样,相等性比较对字符串的编码很敏感,因此在任何比较之前,字符串都必须始终转换为通用编码。Object#equals(Object) 的行为类似于 EqualNode,但由于此方法没有 expectedEncoding 参数,它将自动确定字符串的通用编码。如果字符串的编码不相等,TruffleString 将检查一个字符串是否与另一个字符串的编码二进制兼容,如果是,则匹配它们的内容。否则,字符串被认为不相等,不会应用自动转换。

请注意,由于 TruffleStringhashCodeequals 方法对字符串编码敏感,因此在将 TruffleString 对象用作 HashMap 中的键之前,必须始终将它们转换为通用编码。

TruffleString 还提供了三个比较节点 CompareBytesNodeCompareCharsUTF16NodeCompareIntsUTF32Node,分别按字节、按字符和按整数比较字符串。

连接 #

连接通过 ConcatNode 完成。此操作要求两个字符串都使用 expectedEncoding,这也是结果字符串的编码。延迟连接 通过 lazy 参数支持。当两个字符串被延迟连接时,新字符串的内部数组的分配和初始化将被延迟,直到另一个操作需要直接访问该数组。可以使用 MaterializeNode 显式触发此类“延迟连接字符串”的具体化。这在循环中访问字符串之前很有用,例如在以下示例中

import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.strings.TruffleString;

abstract static class SomeNode extends Node {

    @Specialization
    static TruffleString someSpecialization(
            TruffleString utf8StringA,
            TruffleString utf8StringB,
            @Cached TruffleString.ConcatNode concatNode,
            @Cached TruffleString.MaterializeNode materializeNode,
            @Cached TruffleString.ReadByteNode readByteNode) {
        // lazy concatenation
        TruffleString lazyConcatenated = concatNode.execute(utf8StringA, utf8StringB, TruffleString.Encoding.UTF_8, /* lazy */ true);

        // explicit materialization
        TruffleString materialized = materializeNode.execute(lazyConcatenated, TruffleString.Encoding.UTF_8);

        int byteLength = materialized.byteLength(TruffleString.Encoding.UTF_8);
        for (int i = 0; i < byteLength; i++) {
            // string is guaranteed to be materialized here, so no slow materialization code can end up in this loop
            System.out.printf("%x%n", readByteNode.execute(materialized, i, TruffleString.Encoding.UTF_8));
        }
    }
}

子字符串 #

子字符串可以通过 SubstringNodeSubstringByteIndexNode 创建,它们分别使用基于码点的索引和基于字节的索引。子字符串也可以是 lazy,这意味着不会为结果字符串创建新的数组,而是重用父字符串的数组,并仅使用传递给子字符串节点的偏移量和长度进行访问。目前,延迟子字符串的内部数组永远不会被截断(即被替换为具有字符串精确长度的新数组)。请注意,此行为实际上会在创建延迟子字符串时创建内存泄漏。这可能会造成问题的极端示例:给定一个大小为 100 兆字节的字符串,从此字符串创建的任何延迟子字符串都将保持 100 兆字节数组的活动状态,即使原始字符串被垃圾收集器释放。谨慎使用延迟子字符串。

java.lang.String 的互操作性 #

TruffleString 提供 FromJavaStringNode 用于将 java.lang.String 转换为 TruffleString。要从 TruffleString 转换为 java.lang.String,请使用 ToJavaStringNode。此节点将在内部将字符串转换为 UTF-16(如果需要),并从该表示形式创建 java.lang.String

Object#toString() 使用 ToJavaStringNode 的未缓存版本实现,应避免在快速路径上使用它。

import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.strings.TruffleString;

abstract static class SomeNode extends Node {

    @Specialization
    static void someSpecialization(
            @Cached TruffleString.FromJavaStringNode fromJavaStringNode,
            @Cached TruffleString.SwitchEncodingNode switchEncodingNode,
            @Cached TruffleString.ToJavaStringNode toJavaStringNode,
            @Cached TruffleString.ReadByteNode readByteNode) {
        TruffleString utf16String = fromJavaStringNode.execute("foo", TruffleString.Encoding.UTF_16);
        TruffleString utf8String = switchEncodingNode.execute(utf16String, TruffleString.Encoding.UTF_8);
        System.out.println(toJavaStringNode.execute(utf8String));
    }
}

TruffleString 还公开了 #toStringDebug() 用于调试目的。不要将此方法用于除调试之外的任何目的,因为它的返回值未指定,可能会随时更改。

java.lang.String 的区别 #

java.lang.String 切换到 TruffleString 时,应考虑以下事项。

  • TruffleString 实例的静态开销大于 java.lang.String 对象的静态开销。一个 TruffleString 对象包含 2 个指针字段、4 个 int 字段和 4 个 byte 字段,这通常会导致总对象大小为 40 字节(对象头为 12 字节,每个指针 4 字节,使用压缩 oops,8 字节内存对齐)。一个 java.lang.String 对象包含一个指针字段、一个 int 字段和一个 byte 字段,在相同条件下,总对象大小为 24 字节。这种内存占用量的差异可能会对某些情况下生成大量小字符串的情况产生负面影响。
  • TruffleString 就像 java.lang.String 一样执行字符串压缩。
  • 如果您的语言需要将字符串转换为其他编码,例如 UTF-8(在 Web 应用程序中非常常见),TruffleString 可以将此操作变为无操作,如果字符串不包含特殊字符。例如,仅包含 ASCII 的字符串可以重新解释为几乎任何编码,将仅包含 ASCII 的 UTF-16 字符串转换为 UTF-8 是无操作。在必须对字符串进行转码的情况下,TruffleString 将在原始字符串中缓存转码后的字符串,因此每个字符串和编码仅进行一次转码。
  • 为了使用第三方库,TruffleString 对象必须转换为 java.lang.String 然后再转换回来。为了尽可能地降低成本,TruffleString 在从 java.lang.String 转换为 TruffleString 时重新使用 Java String 的内部字节数组,并在对象本身中缓存从 TruffleString 对象创建的 Java 字符串。
  • TruffleString 提供了 java.lang.String 中没有的附加功能。
    • 延迟连接和字符串视图,这可以显着减少语言可能需要执行的数组复制操作的数量。
    • 对本机内存的 String 视图,完全避免了在使用之前将本机内存复制到 Java 数组的必要性。
    • 通过 codeRange 属性对 String 内容进行分类,这允许对仅包含 ASCII 等字符串进行专门化。这可以显着降低某些字符串操作的复杂性。
  • 所有 TruffleString 操作的性能应与其 java.lang.String 对应物相当或更好。

代码点迭代器 #

TruffleString 提供了 TruffleStringIterator 作为遍历字符串代码点的工具。此方法应优先于在循环中使用 CodePointAtIndexNode,尤其是在 UTF-8 等可变宽度编码中,因为 CodePointAtIndexNode 可能会在每次调用时重新计算给定代码点索引的等效字节索引。

请参见示例。

import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.strings.TruffleString;
import com.oracle.truffle.api.strings.TruffleStringIterator;

abstract static class SomeNode extends Node {

    @Specialization
    static void someSpecialization(
            TruffleString string,
            @Cached TruffleString.CreateCodePointIteratorNode createCodePointIteratorNode,
            @Cached TruffleStringIterator.NextNode nextNode,
            @Cached TruffleString.CodePointLengthNode codePointLengthNode,
            @Cached TruffleString.CodePointAtIndexNode codePointAtIndexNode) {

        // iterating over a string's codepoints using TruffleStringIterator
        TruffleStringIterator iterator = createCodePointIteratorNode.execute(string, TruffleString.Encoding.UTF_8);
        while (iterator.hasNext()) {
            System.out.printf("%x%n", nextNode.execute(iterator));
        }

        // suboptimal variant: using CodePointAtIndexNode in a loop
        int codePointLength = codePointLengthNode.execute(string, TruffleString.Encoding.UTF_8);
        for (int i = 0; i < codePointLength; i++) {
            // performance problem: codePointAtIndexNode may have to calculate the byte index corresponding
            // to codepoint index i for every loop iteration
            System.out.printf("%x%n", codePointAtIndexNode.execute(string, i, TruffleString.Encoding.UTF_8));
        }
    }
}

可变字符串 #

TruffleString 还提供了一个名为 MutableTruffleString 的可变字符串变体,它也被 TruffleString 的所有节点接受。MutableTruffleString **不是线程安全的**,并允许通过 WriteByteNode 覆盖其内部字节数组或本机指针中的字节。内部数组或本机指针的内容也可以在外部修改,但相应的 MutableTruffleString 必须通过 notifyExternalMutation() 通知此更改。MutableTruffleString **不是** Truffle 交互类型,必须通过 TruffleString.AsTruffleString 转换为不可变的 TruffleString,然后才能跨越语言边界。

联系我们