This is an automated email from the ASF dual-hosted git repository. chaokunyang pushed a commit to branch update_usage in repository https://gitbox.apache.org/repos/asf/fory-site.git
commit a6a5ea69c48d4355027a42c35c7e718b76065afb Author: chaokunyang <[email protected]> AuthorDate: Tue Mar 24 12:57:16 2026 +0800 update usage doc --- docs/start/install.md | 74 ++- docs/start/usage.md | 374 ++++++++++-- .../current/start/install.md | 106 +++- .../current/start/usage.md | 671 ++++++++++++++++----- 4 files changed, 967 insertions(+), 258 deletions(-) diff --git a/docs/start/install.md b/docs/start/install.md index 9f73a9c5d2..3f140b8bb6 100644 --- a/docs/start/install.md +++ b/docs/start/install.md @@ -4,13 +4,13 @@ title: Install sidebar_position: 0 --- -The official Apache Fory™ releases are provided as source artifacts. +Apache Fory™ releases are available both as source artifacts and language-specific packages. -For source download, please see Apache Fory™ [download](https://fory.apache.org/download) page. +For source downloads, see the Apache Fory™ [download](https://fory.apache.org/download) page. ## Java -To add a dependency on Apache Fory™ using Maven, use the following: +Use Maven to add Apache Fory™: ```xml <dependency> @@ -23,7 +23,7 @@ To add a dependency on Apache Fory™ using Maven, use the following: <dependency> <groupId>org.apache.fory</groupId> <artifactId>fory-format</artifactId> - <version>0.13.1</version> + <version>0.16.0</version> </dependency> --> <!-- SIMD acceleration for array compression (Java 16+) --> @@ -31,14 +31,14 @@ To add a dependency on Apache Fory™ using Maven, use the following: <dependency> <groupId>org.apache.fory</groupId> <artifactId>fory-simd</artifactId> - <version>0.13.1</version> + <version>0.16.0</version> </dependency> --> ``` ## Scala -To add a dependency on Apache Fory™ scala for scala 2.13 with maven, use the following: +Scala 2.13 with Maven: ```xml <dependency> @@ -48,7 +48,7 @@ To add a dependency on Apache Fory™ scala for scala 2.13 with maven, use the f </dependency> ``` -To add a dependency on Apache Fory™ scala for scala 3 with maven, use the following: +Scala 3 with Maven: ```xml <dependency> @@ -58,13 +58,13 @@ To add a dependency on Apache Fory™ scala for scala 3 with maven, use the foll </dependency> ``` -To add a dependency on Apache Fory™ scala for scala 2.13 with sbt, use the following: +Scala 2.13 with sbt: ```sbt libraryDependencies += "org.apache.fory" % "fory-scala_2.13" % "0.16.0" ``` -To add a dependency on Apache Fory™ scala for scala 3 with sbt, use the following: +Scala 3 with sbt: ```sbt libraryDependencies += "org.apache.fory" % "fory-scala_3" % "0.16.0" @@ -72,7 +72,7 @@ libraryDependencies += "org.apache.fory" % "fory-scala_3" % "0.16.0" ## Kotlin -To add a dependency on Apache Fory™ kotlin with maven, use the following: +Add Apache Fory™ Kotlin with Maven: ```xml <dependency> @@ -89,14 +89,20 @@ python -m pip install --upgrade pip pip install pyfory==0.16.0 ``` +## Go + +```bash +go get github.com/apache/fory/go/[email protected] +``` + ## Rust ```toml [dependencies] -fory = "0.14" +fory = "0.16.0" ``` -or just execute command: +Or use `cargo add`: ```bash cargo add [email protected] @@ -104,4 +110,46 @@ cargo add [email protected] ## JavaScript -Apache Fory™ is NOT yet available on npm, please install from source code now. +Install the core JavaScript runtime: + +```bash +npm install @apache-fory/core +``` + +Optional native acceleration on Node.js 20+: + +```bash +npm install @apache-fory/hps +``` + +## C# + +Install the `Apache.Fory` NuGet package. It includes both the runtime and the source generator for `[ForyObject]` types. + +```bash +dotnet add package Apache.Fory --version 0.16.0 +``` + +```xml +<ItemGroup> + <PackageReference Include="Apache.Fory" Version="0.16.0" /> +</ItemGroup> +``` + +## Swift + +Add Apache Fory™ from the GitHub repository with Swift Package Manager: + +```swift +dependencies: [ + .package(url: "https://github.com/apache/fory.git", exact: "0.16.0") +], +targets: [ + .target( + name: "MyApp", + dependencies: [ + .product(name: "Fory", package: "fory") + ] + ) +] +``` diff --git a/docs/start/usage.md b/docs/start/usage.md index fe52197804..b9093d23cc 100644 --- a/docs/start/usage.md +++ b/docs/start/usage.md @@ -10,11 +10,13 @@ This section provides quick examples for getting started with Apache Fory™. **Always use native mode when working with a single language.** Native mode delivers optimal performance by avoiding the type metadata overhead required for cross-language compatibility. -Xlang mode introduces additional metadata encoding costs and restricts serialization to types that are common across all supported languages. Language-specific types will be rejected during serialization in xlang-mode. +Xlang mode introduces additional metadata encoding costs and restricts serialization to types that are common across all supported languages. Language-specific types will be rejected during serialization in xlang mode. ### Java Serialization -When you don't need cross-language support, use Java mode for optimal performance. +When you do not need cross-language support, use Java mode for optimal performance. + +This example creates a reusable Java-mode runtime, registers a user class, and then performs a basic serialize/deserialize round trip. In production code, keep the `Fory` instance alive and reuse it across requests instead of rebuilding it for every object. ```java import org.apache.fory.*; @@ -27,21 +29,21 @@ public class Example { } public static void main(String[] args) { - // Create Fory instance - should be reused across serializations + // Create a Fory instance once and reuse it. BaseFory fory = Fory.builder() .withLanguage(Language.JAVA) .requireClassRegistration(true) - // replace `build` with `buildThreadSafeFory` for Thread-Safe Usage + // Replace `build` with `buildThreadSafeFory` for thread-safe usage. .build(); - // Register your classes (required when class registration is enabled) fory.register(Person.class); - // Serialize + Person person = new Person(); person.name = "chaokunyang"; person.age = 28; + byte[] bytes = fory.serialize(person); Person result = (Person) fory.deserialize(bytes); - System.out.println(result.name + " " + result.age); // Output: chaokunyang 28 + System.out.println(result.name + " " + result.age); } } ``` @@ -50,7 +52,9 @@ For detailed Java usage including compatibility modes, compression, and advanced ### Python Serialization -Python native mode provides a high-performance drop-in replacement for pickle/cloudpickle with better speed and compatibility. +Python native mode provides a high-performance drop-in replacement for `pickle` and `cloudpickle`. + +The example below uses a dataclass with explicit integer typing so Fory can preserve the intended schema efficiently. As with other runtimes, create the `Fory` instance once, register your types once, and then reuse it for repeated serialization. ```python from dataclasses import dataclass @@ -61,21 +65,187 @@ class Person: name: str age: pyfory.int32 -# Create Fory instance - should be reused across serializations fory = pyfory.Fory() -# Register your classes (required when class registration is enabled) fory.register_type(Person) + person = Person(name="chaokunyang", age=28) data = fory.serialize(person) result = fory.deserialize(data) -print(result.name, result.age) # Output: chaokunyang 28 +print(result.name, result.age) ``` For detailed Python usage including type hints, compatibility modes, and advanced features, see [Python Guide](../guide/python/index.md). +### Go Serialization + +Go native mode is the default. Register your structs once, then reuse the same `Fory` instance. + +The Go runtime works naturally with exported struct fields and explicit type registration. This snippet shows the standard flow: create `Fory`, register a struct type, serialize a value, and deserialize into a destination struct. + +```go +package main + +import ( + "fmt" + + "github.com/apache/fory/go/fory" +) + +type Person struct { + Name string + Age int32 +} + +func main() { + f := fory.New() + if err := f.RegisterStruct(Person{}, 1); err != nil { + panic(err) + } + + person := &Person{Name: "chaokunyang", Age: 28} + data, err := f.Serialize(person) + if err != nil { + panic(err) + } + + var result Person + if err := f.Deserialize(data, &result); err != nil { + panic(err) + } + + fmt.Printf("%s %d\n", result.Name, result.Age) +} +``` + +For detailed Go usage including configuration, struct tags, and schema evolution, see [Go Guide](../guide/go/index.md). + +### C# Serialization + +C# native serialization uses the `Apache.Fory` runtime together with `[ForyObject]` model types. + +In C#, the usual pattern is to mark your model with `[ForyObject]`, build a runtime once, and register the type before use. The example demonstrates the strongly typed `Serialize` and `Deserialize<T>` APIs that fit normal .NET application code. + +```csharp +using Apache.Fory; + +[ForyObject] +public sealed class Person +{ + public string Name { get; set; } = string.Empty; + public int Age { get; set; } +} + +Fory fory = Fory.Builder().Build(); +fory.Register<Person>(1); + +Person person = new() { Name = "chaokunyang", Age = 28 }; +byte[] data = fory.Serialize(person); +Person result = fory.Deserialize<Person>(data); + +Console.WriteLine($"{result.Name} {result.Age}"); +``` + +For detailed C# usage including source generators, references, and schema evolution, see [C# Guide](../guide/csharp/index.md). + +### Swift Serialization + +Swift native serialization uses `@ForyObject` models and the `Fory` runtime directly. + +Swift uses macro-based model definitions, so the example starts by annotating the type with `@ForyObject`, then registers the type ID and performs a typed round trip. This is the recommended starting point for app-side Swift usage. + +```swift +import Fory + +@ForyObject +struct Person: Equatable { + var name: String = "" + var age: Int32 = 0 +} + +let fory = Fory() +fory.register(Person.self, id: 1) + +let person = Person(name: "chaokunyang", age: 28) +let data = try fory.serialize(person) +let result: Person = try fory.deserialize(data) + +print("\(result.name) \(result.age)") +``` + +For detailed Swift usage including polymorphism, schema evolution, and troubleshooting, see [Swift Guide](../guide/swift/index.md). + +### Rust Serialization + +Rust native mode uses `Fory::default()` and derive macros for compile-time type-safe serialization. The normal pattern is to derive `ForyObject`, register the type once, and then reuse the configured runtime for repeated serialization. + +```rust +use fory::{Error, Fory, ForyObject}; + +#[derive(ForyObject, Debug, PartialEq)] +struct Person { + name: String, + age: i32, +} + +fn main() -> Result<(), Error> { + let mut fory = Fory::default(); + fory.register::<Person>(1)?; + + let person = Person { + name: "chaokunyang".to_string(), + age: 28, + }; + + let bytes = fory.serialize(&person)?; + let result: Person = fory.deserialize(&bytes)?; + assert_eq!(person, result); + Ok(()) +} +``` + +For detailed Rust usage including references, polymorphism, and row format support, see [Rust Guide](../guide/rust/index.md). + +### C++ Serialization + +C++ native mode uses the `FORY_STRUCT` macro to describe serializable fields and a configured `Fory` runtime to encode and decode values. For single-language C++ usage, set `xlang(false)` explicitly so the runtime stays in native mode. + +```cpp +#include "fory/serialization/fory.h" + +using namespace fory::serialization; + +struct Person { + std::string name; + int32_t age; + + bool operator==(const Person &other) const { + return name == other.name && age == other.age; + } + + FORY_STRUCT(Person, name, age); +}; + +int main() { + auto fory = Fory::builder().xlang(false).build(); + fory.register_struct<Person>(1); + + Person person{"chaokunyang", 28}; + + auto bytes = fory.serialize(person); + auto result = fory.deserialize<Person>(bytes.value()); + assert(result.ok()); + assert(person == result.value()); + return 0; +} +``` + +For detailed C++ usage including `FORY_STRUCT`, thread safety, and schema evolution, see [C++ Guide](../guide/cpp/index.md). + ### Scala Serialization -Scala native mode provides optimized serialization for Scala-specific types including case classes, collections, and Option types. +Scala native mode provides optimized serialization for Scala-specific types including case classes, collections, and `Option`. + +For Scala projects, register the Scala serializers first so Fory understands Scala-specific data structures correctly. After that, you can register your case classes and use the same core API as the Java runtime. ```scala import org.apache.fory.Fory @@ -86,18 +256,16 @@ case class Person(name: String, age: Int) object Example { def main(args: Array[String]): Unit = { - // Create Fory instance - should be reused across serializations val fory = Fory.builder() .withLanguage(Language.JAVA) .requireClassRegistration(true) .build() - // Register Scala serializers for Scala-specific types ScalaSerializers.registerSerializers(fory) - // Register your case classes fory.register(classOf[Person]) + val bytes = fory.serialize(Person("chaokunyang", 28)) val result = fory.deserialize(bytes).asInstanceOf[Person] - println(s"${result.name} ${result.age}") // Output: chaokunyang 28 + println(s"${result.name} ${result.age}") } } ``` @@ -108,6 +276,8 @@ For detailed Scala usage including collection serialization and integration patt Kotlin native mode provides optimized serialization for Kotlin-specific types including data classes, nullable types, and Kotlin collections. +Kotlin follows the same builder flow as Java, with an extra registration step for Kotlin-specific serializers. The example uses a data class and shows the minimal setup needed for efficient native serialization. + ```kotlin import org.apache.fory.Fory import org.apache.fory.config.Language @@ -116,18 +286,16 @@ import org.apache.fory.serializer.kotlin.KotlinSerializers data class Person(val name: String, val age: Int) fun main() { - // Create Fory instance - should be reused across serializations val fory = Fory.builder() .withLanguage(Language.JAVA) .requireClassRegistration(true) .build() - // Register Kotlin serializers for Kotlin-specific types KotlinSerializers.registerSerializers(fory) - // Register your data classes fory.register(Person::class.java) + val bytes = fory.serialize(Person("chaokunyang", 28)) val result = fory.deserialize(bytes) as Person - println("${result.name} ${result.age}") // Output: chaokunyang 28 + println("${result.name} ${result.age}") } ``` @@ -135,12 +303,14 @@ For detailed Kotlin usage including null safety and default value support, see [ ## Cross-Language Serialization -**Only use xlang mode when you need cross-language data exchange.** Xlang mode adds type metadata overhead for cross-language compatibility and only supports types that can be mapped across all languages. For single-language use cases, always prefer native mode for better performance. +**Only use xlang mode when you need cross-language data exchange.** Xlang mode adds type metadata overhead for cross-language compatibility and only supports types that can be mapped across all languages. -The following examples demonstrate serializing a `Person` object across Java and Rust. For other languages (Python, Go, JavaScript, etc.), simply set the language mode to `XLANG` and follow the same pattern. +The examples below use the same `Person` schema across multiple runtimes. In every language, enable xlang mode and register the type with the same ID or the same fully qualified name. ### Java +Java xlang usage is the baseline pattern for JVM services. Enable `Language.XLANG`, register the type with a stable ID or name, and make sure every peer language uses the same mapping. + ```java import org.apache.fory.*; import org.apache.fory.config.*; @@ -149,27 +319,67 @@ public class XlangExample { public record Person(String name, int age) {} public static void main(String[] args) { - // Create Fory instance with XLANG mode Fory fory = Fory.builder() .withLanguage(Language.XLANG) .build(); - // Register with cross-language type id/name fory.register(Person.class, 1); // fory.register(Person.class, "example.Person"); + Person person = new Person("chaokunyang", 28); byte[] bytes = fory.serialize(person); - // bytes can be deserialized by Rust, Python, Go, or other languages Person result = (Person) fory.deserialize(bytes); - System.out.println(result.name + " " + result.age); // Output: chaokunyang 28 + System.out.println(result.name() + " " + result.age()); } } ``` +### Go + +Go xlang mode is enabled through `WithXlang(true)`. The important part is not the Go syntax itself, but keeping the registered type identity aligned with every other language that reads or writes the payload. + +```go +package main + +import ( + "fmt" + + "github.com/apache/fory/go/fory" +) + +type Person struct { + Name string + Age int32 +} + +func main() { + f := fory.New(fory.WithXlang(true)) + if err := f.RegisterStruct(Person{}, 1); err != nil { + panic(err) + } + + person := &Person{Name: "chaokunyang", Age: 28} + data, err := f.Serialize(person) + if err != nil { + panic(err) + } + + var result Person + if err := f.Deserialize(data, &result); err != nil { + panic(err) + } + + fmt.Printf("%s %d\n", result.Name, result.Age) +} +``` + ### Rust +Rust follows the same cross-language contract, but expresses it through derived traits and explicit registration on the `Fory` instance. Once the type ID matches the other runtimes, the payload can move across language boundaries safely. + ```rust use fory::{Fory, ForyObject}; +use std::error::Error; #[derive(ForyObject, Debug)] struct Person { @@ -177,74 +387,114 @@ struct Person { age: i32, } -fn main() -> Result<(), Error> { - let mut fory = Fory::default(); +fn main() -> Result<(), Box<dyn Error>> { + let mut fory = Fory::default().xlang(true); fory.register::<Person>(1)?; // fory.register_by_name::<Person>("example.Person")?; + let person = Person { name: "chaokunyang".to_string(), age: 28, }; let bytes = fory.serialize(&person); - // bytes can be deserialized by Java, Python, Go, or other languages let result: Person = fory.deserialize(&bytes)?; - println!("{} {}", result.name, result.age); // Output: chaokunyang 28 + println!("{} {}", result.name, result.age); + Ok(()) } ``` -### Golang - -```go -type Person struct { - name: string - age: i32 -} -fory := fory.NewFory(true) -fory.Register(Person{}, 1) -person := Person{"chaokunyang", 28} -bytes, err := fory.Marshal(person) -var p Person -err = fory.Unmarshal(bytes, &p) -``` - ### JavaScript +JavaScript cross-language support is schema-driven. Instead of registering a class, you describe the payload shape with `Type.object(...)`, then use the returned serializer pair to encode and decode values. + ```javascript -import Fory, { Type } from "@apache-fory/fory"; +import Fory, { Type } from "@apache-fory/core"; /** - * @apache-fory/hps use v8's fast-calls-api that can be called directly by jit, ensure that the version of Node is 20 or above. - * Experimental feature, installation success cannot be guaranteed at this moment - * If you are unable to install the module, replace it with `const hps = null;` - **/ + * `@apache-fory/hps` uses V8 fast calls directly from JIT. + * Use Node.js 20+ when enabling it. + * If installation fails, replace it with `const hps = null;`. + */ import hps from "@apache-fory/hps"; -// Now we describe data structures using JSON, but in the future, we will use more ways. const description = Type.object("example.Person", { name: Type.string(), age: Type.int32(), }); + const fory = new Fory({ hps }); const { serialize, deserialize } = fory.registerSerializer(description); -const input = serialize({ name: "chaokunyang", age: 28 }); -const result = deserialize(input); + +const payload = serialize({ name: "chaokunyang", age: 28 }); +const result = deserialize(payload); console.log(result); ``` +### C# + +C# cross-language code looks similar to native usage, but the runtime is explicitly configured for xlang and compatible mode. Use the same type ID or namespace/name mapping as your Java, Go, Swift, or Rust peers. + +```csharp +using Apache.Fory; + +[ForyObject] +public sealed class Person +{ + public string Name { get; set; } = string.Empty; + public int Age { get; set; } +} + +Fory fory = Fory.Builder() + .Xlang(true) + .Compatible(true) + .Build(); + +fory.Register<Person>(1); + +Person person = new() { Name = "chaokunyang", Age = 28 }; +byte[] payload = fory.Serialize(person); +Person result = fory.Deserialize<Person>(payload); + +Console.WriteLine($"{result.Name} {result.Age}"); +``` + +### Swift + +Swift cross-language serialization uses the same `@ForyObject` model style as native mode, but you create the runtime with `xlang: true`. Stable registration IDs are still the key requirement for interoperability. + +```swift +import Fory + +@ForyObject +struct Person: Equatable { + var name: String = "" + var age: Int32 = 0 +} + +let fory = Fory(xlang: true, trackRef: false, compatible: true) +fory.register(Person.self, id: 1) + +let person = Person(name: "chaokunyang", age: 28) +let data = try fory.serialize(person) +let result: Person = try fory.deserialize(data) + +print("\(result.name) \(result.age)") +``` + ### Key Points -- Use `Language.XLANG` mode in all languages -- Register types with **consistent IDs or names** across all languages: - - **By ID** (`fory.register(Person.class, 1)`): Faster serialization, more compact encoding, but requires coordination to avoid ID conflicts - - **By name** (`fory.register(Person.class, "example.Person")`): More flexible, less prone to conflicts, easier to manage across teams, but slightly larger encoding -- Type IDs/names must match across all languages for successful deserialization -- Only use types that have cross-language mappings (see [Type Mapping](../specification/xlang_type_mapping.md)) +- Enable xlang mode in every runtime (`Language.XLANG`, `WithXlang(true)`, `Xlang(true)`, `Fory(xlang: true, ...)`, and so on). +- Register types with **consistent IDs or names** across all languages. +- ID-based registration is more compact and faster, but it requires coordination to avoid conflicts. +- Name-based registration is easier to manage across teams, but it produces slightly larger payloads. +- Only use types that have cross-language mappings; see [Type Mapping](../specification/xlang_type_mapping.md). -For examples with **circular references**, **shared references**, and **polymorphism** across languages, see: +For examples with circular references, shared references, and polymorphism across languages, see: - [Cross-Language Serialization Guide](../guide/xlang/index.md) -- [Java Serialization Guide - Cross Language](../guide/java/cross-language.md) -- [Python Guide - Cross Language](../guide/python/cross-language.md) +- [Go Guide - Cross Language](../guide/go/cross-language.md) +- [C# Guide - Cross Language](../guide/csharp/cross-language.md) +- [Swift Guide - Cross Language](../guide/swift/cross-language.md) ## Row Format Encoding diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/start/install.md b/i18n/zh-CN/docusaurus-plugin-content-docs/current/start/install.md index 9b6077dc6e..c45c9bc2a9 100644 --- a/i18n/zh-CN/docusaurus-plugin-content-docs/current/start/install.md +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/start/install.md @@ -4,98 +4,152 @@ title: 安装 Apache Fory™ sidebar_position: 0 --- -Apache Fory™ 源码下载请参见 Apache Fory™ [download](https://github.com/apache/fory/releases)页面。 +Apache Fory™ 同时提供源码发布物和各语言对应的软件包。 -## 安装 Apache Fory™ Java +源码下载请参见 Apache Fory™ [download](https://fory.apache.org/download) 页面。 -要使用 Maven 添加对 Apache Fory™ 的依赖,请使用以下配置: +## Java + +使用 Maven 添加 Apache Fory™: ```xml <dependency> <groupId>org.apache.fory</groupId> <artifactId>fory-core</artifactId> - <version>0.14.1</version> + <version>0.16.0</version> </dependency> -<!-- Optional row format support --> +<!-- 可选:row format 支持 --> <!-- <dependency> <groupId>org.apache.fory</groupId> <artifactId>fory-format</artifactId> - <version>0.13.1</version> + <version>0.16.0</version> </dependency> --> -<!-- SIMD acceleration for array compression (Java 16+) --> +<!-- 可选:数组压缩 SIMD 加速(Java 16+) --> <!-- <dependency> <groupId>org.apache.fory</groupId> <artifactId>fory-simd</artifactId> - <version>0.13.1</version> + <version>0.16.0</version> </dependency> --> ``` -## 安装 Apache Fory™ Scala +## Scala -要使用 Maven 添加 scala 2.13 的 Fory scala 依赖,请使用以下配置: +Scala 2.13 的 Maven 依赖: ```xml <dependency> <groupId>org.apache.fory</groupId> <artifactId>fory-scala_2.13</artifactId> - <version>0.14.1</version> + <version>0.16.0</version> </dependency> ``` -要使用 Maven 添加 scala 3 的 Fory scala 依赖,请使用以下配置: +Scala 3 的 Maven 依赖: ```xml <dependency> <groupId>org.apache.fory</groupId> <artifactId>fory-scala_3</artifactId> - <version>0.14.1</version> + <version>0.16.0</version> </dependency> ``` -要使用 sbt 添加 scala 2.13 的 Fory scala 依赖,请使用以下配置: +Scala 2.13 的 sbt 依赖: ```sbt -libraryDependencies += "org.apache.fory" % "fory-scala_2.13" % "0.14.1" +libraryDependencies += "org.apache.fory" % "fory-scala_2.13" % "0.16.0" ``` -要使用 sbt 添加 scala 3 的 Fory scala 依赖,请使用以下配置: +Scala 3 的 sbt 依赖: ```sbt -libraryDependencies += "org.apache.fory" % "fory-scala_3" % "0.14.1" +libraryDependencies += "org.apache.fory" % "fory-scala_3" % "0.16.0" ``` -## 安装 Apache Fory™ Kotlin +## Kotlin -To add a dependency on Apache Fory™kotlin with maven, use the following: +使用 Maven 添加 Apache Fory™ Kotlin: ```xml <dependency> <groupId>org.apache.fory</groupId> <artifactId>fory-kotlin</artifactId> - <version>0.14.1</version> + <version>0.16.0</version> </dependency> ``` -## 安装 Apache Fory™ Python +## Python ```bash python -m pip install --upgrade pip -pip install pyfory==0.14.1 +pip install pyfory==0.16.0 +``` + +## Go + +```bash +go get github.com/apache/fory/go/[email protected] ``` -## 安装 Apache Fory™ Rust +## Rust ```toml [dependencies] -fory = "0.14" +fory = "0.16.0" +``` + +或者使用 `cargo add`: + +```bash +cargo add [email protected] +``` + +## JavaScript + +安装 JavaScript 核心运行时: + +```bash +npm install @apache-fory/core +``` + +可选的原生加速模块(需要 Node.js 20+): + +```bash +npm install @apache-fory/hps ``` -或者直接执行以下命令: +## C# + +安装 `Apache.Fory` NuGet 包。它同时包含运行时和 `[ForyObject]` 类型所需的源代码生成器。 ```bash -cargo add [email protected] +dotnet add package Apache.Fory --version 0.16.0 +``` + +```xml +<ItemGroup> + <PackageReference Include="Apache.Fory" Version="0.16.0" /> +</ItemGroup> +``` + +## Swift + +使用 Swift Package Manager 从 GitHub 仓库引入 Apache Fory™: + +```swift +dependencies: [ + .package(url: "https://github.com/apache/fory.git", exact: "0.16.0") +], +targets: [ + .target( + name: "MyApp", + dependencies: [ + .product(name: "Fory", package: "fory") + ] + ) +] ``` diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/start/usage.md b/i18n/zh-CN/docusaurus-plugin-content-docs/current/start/usage.md index bd9ce3a1b3..40c352982d 100644 --- a/i18n/zh-CN/docusaurus-plugin-content-docs/current/start/usage.md +++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/start/usage.md @@ -4,233 +4,590 @@ title: Apache Fory™ 使用 sidebar_position: 1 --- -本章节演示不同编程语言使用 Apache Fory™ 进行序列化。 +本章节提供 Apache Fory™ 的快速入门示例。 -## Java 序列化 +## 原生序列化 + +**当你只在单一语言内使用时,请始终选择原生模式。** 原生模式不需要为跨语言兼容写入额外类型元信息,因此性能最好。 + +xlang 模式会引入额外的元信息编码开销,并且只允许序列化所有受支持语言都能映射的类型。语言特有类型在 xlang 模式下会被拒绝。 + +### Java 序列化 + +如果不需要跨语言支持,请使用 Java 模式以获得最佳性能。 + +下面的示例展示了最基本的 Java 原生用法:创建可复用的 Java 模式运行时、注册用户类型,然后完成一次序列化和反序列化往返。实际项目中不要为每个对象重新创建 `Fory` 实例,而应长期复用同一个实例。 ```java -import java.util.List; -import java.util.Arrays; -import io.fory.*; +import org.apache.fory.*; +import org.apache.fory.config.*; public class Example { + public static class Person { + String name; + int age; + } + public static void main(String[] args) { - SomeClass object = new SomeClass(); - // Note that Fory instances should be reused between - // multiple serializations of different objects. - Fory fory = Fory.builder().withLanguage(Language.JAVA) - // Allow to deserialize objects unknown types, - // more flexible but less secure. - // .requireClassRegistration(false) + // 创建一次 Fory 实例并重复复用。 + BaseFory fory = Fory.builder() + .withLanguage(Language.JAVA) + .requireClassRegistration(true) + // 如果需要线程安全用法,请将 `build` 替换为 `buildThreadSafeFory`。 .build(); - // Registering types can reduce class name serialization overhead, but not mandatory. - // If secure mode enabled, all custom types must be registered. - fory.register(SomeClass.class); - byte[] bytes = fory.serialize(object); - System.out.println(fory.deserialize(bytes)); + fory.register(Person.class); + + Person person = new Person(); + person.name = "chaokunyang"; + person.age = 28; + + byte[] bytes = fory.serialize(person); + Person result = (Person) fory.deserialize(bytes); + System.out.println(result.name + " " + result.age); } } ``` -## Scala序列化 +关于兼容模式、压缩和更多高级特性,请参见 [Java 序列化指南](../guide/java/index.md)。 + +### Python 序列化 + +Python 原生模式可以作为 `pickle` 和 `cloudpickle` 的高性能替代方案。 + +这个示例使用 dataclass 和显式整数类型注解,让 Fory 能以更清晰的 Schema 进行高效序列化。与其他语言一样,推荐只创建一次 `Fory` 实例、只注册一次类型,然后在后续调用中重复使用。 + +```python +from dataclasses import dataclass +import pyfory + +@dataclass +class Person: + name: str + age: pyfory.int32 + +fory = pyfory.Fory() +fory.register_type(Person) + +person = Person(name="chaokunyang", age=28) +data = fory.serialize(person) +result = fory.deserialize(data) +print(result.name, result.age) +``` + +关于类型注解、兼容模式和更多高级特性,请参见 [Python 指南](../guide/python/index.md)。 + +### Go 序列化 + +Go 原生模式默认启用。注册一次结构体后,重复复用同一个 `Fory` 实例即可。 + +Go 运行时天然适配导出的 struct 字段和显式类型注册。下面的代码演示了最常见的流程:创建 `Fory`、注册结构体类型、序列化一个值,再反序列化到目标结构体中。 + +```go +package main + +import ( + "fmt" + + "github.com/apache/fory/go/fory" +) + +type Person struct { + Name string + Age int32 +} + +func main() { + f := fory.New() + if err := f.RegisterStruct(Person{}, 1); err != nil { + panic(err) + } + + person := &Person{Name: "chaokunyang", Age: 28} + data, err := f.Serialize(person) + if err != nil { + panic(err) + } + + var result Person + if err := f.Deserialize(data, &result); err != nil { + panic(err) + } + + fmt.Printf("%s %d\n", result.Name, result.Age) +} +``` + +关于配置、struct tag 和 Schema 演进,请参见 [Go 指南](../guide/go/index.md)。 + +### C# 序列化 + +C# 原生序列化使用 `Apache.Fory` 运行时和 `[ForyObject]` 模型类型。 + +在 C# 中,常见模式是先用 `[ForyObject]` 标记模型,再创建一次运行时并在使用前注册类型。示例展示的是强类型的 `Serialize` / `Deserialize<T>` API,这也是 .NET 应用中最直接的用法。 + +```csharp +using Apache.Fory; + +[ForyObject] +public sealed class Person +{ + public string Name { get; set; } = string.Empty; + public int Age { get; set; } +} + +Fory fory = Fory.Builder().Build(); +fory.Register<Person>(1); + +Person person = new() { Name = "chaokunyang", Age = 28 }; +byte[] data = fory.Serialize(person); +Person result = fory.Deserialize<Person>(data); + +Console.WriteLine($"{result.Name} {result.Age}"); +``` -````scala +关于源代码生成器、引用跟踪和 Schema 演进,请参见 [C# 指南](../guide/csharp/index.md)。 + +### Swift 序列化 + +Swift 原生序列化直接使用 `@ForyObject` 模型和 `Fory` 运行时。 + +Swift 通过宏定义模型类型,因此示例先使用 `@ForyObject` 标记类型,再注册类型 ID 并完成一次强类型往返。这是 Swift 应用侧最推荐的入门方式。 + +```swift +import Fory + +@ForyObject +struct Person: Equatable { + var name: String = "" + var age: Int32 = 0 +} + +let fory = Fory() +fory.register(Person.self, id: 1) + +let person = Person(name: "chaokunyang", age: 28) +let data = try fory.serialize(person) +let result: Person = try fory.deserialize(data) + +print("\(result.name) \(result.age)") +``` + +关于多态、Schema 演进和常见问题排查,请参见 [Swift 指南](../guide/swift/index.md)。 + +### Rust 序列化 + +Rust 原生模式使用 `Fory::default()` 和 derive 宏来实现编译期类型安全的序列化。常见模式是先为类型派生 `ForyObject`,注册一次类型,再重复复用已经配置好的运行时。 + +```rust +use fory::{Error, Fory, ForyObject}; + +#[derive(ForyObject, Debug, PartialEq)] +struct Person { + name: String, + age: i32, +} + +fn main() -> Result<(), Error> { + let mut fory = Fory::default(); + fory.register::<Person>(1)?; + + let person = Person { + name: "chaokunyang".to_string(), + age: 28, + }; + + let bytes = fory.serialize(&person)?; + let result: Person = fory.deserialize(&bytes)?; + assert_eq!(person, result); + Ok(()) +} +``` + +关于引用、多态和 row format 支持,请参见 [Rust 指南](../guide/rust/index.md)。 + +### C++ 序列化 + +C++ 原生模式使用 `FORY_STRUCT` 宏描述可序列化字段,再通过配置好的 `Fory` 运行时对值进行编码和解码。对于单语言 C++ 场景,建议显式设置 `xlang(false)`,让运行时保持在原生模式。 + +```cpp +#include "fory/serialization/fory.h" + +using namespace fory::serialization; + +struct Person { + std::string name; + int32_t age; + + bool operator==(const Person &other) const { + return name == other.name && age == other.age; + } + + FORY_STRUCT(Person, name, age); +}; + +int main() { + auto fory = Fory::builder().xlang(false).build(); + fory.register_struct<Person>(1); + + Person person{"chaokunyang", 28}; + + auto bytes = fory.serialize(person); + auto result = fory.deserialize<Person>(bytes.value()); + assert(result.ok()); + assert(person == result.value()); + return 0; +} +``` + +关于 `FORY_STRUCT`、线程安全和 Schema 演进,请参见 [C++ 指南](../guide/cpp/index.md)。 + +### Scala 序列化 + +Scala 原生模式对 case class、集合和 `Option` 等 Scala 特有类型提供了优化支持。 + +在 Scala 项目中,应先注册 Scala 专用序列化器,让 Fory 正确理解 Scala 特有的数据结构。完成这一步后,就可以像 Java 运行时一样注册 case class 并执行序列化。 + +```scala import org.apache.fory.Fory +import org.apache.fory.config.Language import org.apache.fory.serializer.scala.ScalaSerializers -case class Person(name: String, id: Long, github: String) -case class Point(x : Int, y : Int, z : Int) - -object ScalaExample { - val fory: Fory = Fory.builder().withScalaOptimizationEnabled(true).build() - // Register optimized fory serializers for scala - ScalaSerializers.registerSerializers(fory) - fory.register(classOf[Person]) - fory.register(classOf[Point]) +case class Person(name: String, age: Int) +object Example { def main(args: Array[String]): Unit = { - val p = Person("Shawn Yang", 1, "https://github.com/chaokunyang") - println(fory.deserialize(fory.serialize(p))) - println(fory.deserialize(fory.serialize(Point(1, 2, 3)))) + val fory = Fory.builder() + .withLanguage(Language.JAVA) + .requireClassRegistration(true) + .build() + ScalaSerializers.registerSerializers(fory) + fory.register(classOf[Person]) + + val bytes = fory.serialize(Person("chaokunyang", 28)) + val result = fory.deserialize(bytes).asInstanceOf[Person] + println(s"${result.name} ${result.age}") } } +``` + +关于集合序列化和集成模式,请参见 [Scala 指南](../guide/scala/index.md)。 + +### Kotlin 序列化 + +Kotlin 原生模式对 data class、可空类型和 Kotlin 集合提供了优化支持。 + +Kotlin 的整体流程与 Java 类似,只是额外需要注册 Kotlin 专用序列化器。下面的示例使用 data class,展示了进行高效原生序列化所需的最小配置。 -## Kotlin序列化 ```kotlin import org.apache.fory.Fory -import org.apache.fory.ThreadSafeFory +import org.apache.fory.config.Language import org.apache.fory.serializer.kotlin.KotlinSerializers -data class Person(val name: String, val id: Long, val github: String) -data class Point(val x : Int, val y : Int, val z : Int) +data class Person(val name: String, val age: Int) -fun main(args: Array<String>) { - // 注意: 下面的Fory初始化代码应该只执行一次,而不是在每次序列化前都运行 - val fory: ThreadSafeFory = Fory.builder().requireClassRegistration(true).buildThreadSafeFory() +fun main() { + val fory = Fory.builder() + .withLanguage(Language.JAVA) + .requireClassRegistration(true) + .build() KotlinSerializers.registerSerializers(fory) fory.register(Person::class.java) - fory.register(Point::class.java) - val p = Person("Shawn Yang", 1, "https://github.com/chaokunyang") - println(fory.deserialize(fory.serialize(p))) - println(fory.deserialize(fory.serialize(Point(1, 2, 3)))) + val bytes = fory.serialize(Person("chaokunyang", 28)) + val result = fory.deserialize(bytes) as Person + println("${result.name} ${result.age}") } -```` +``` + +关于空安全和默认值支持,请参见 [kotlin/README.md](https://github.com/apache/fory/blob/main/kotlin/README.md)。 ## 跨语言序列化 +**只有在确实需要跨语言数据交换时才使用 xlang 模式。** xlang 模式会为跨语言兼容增加类型元信息开销,并且只支持能够在所有语言之间映射的类型。 + +下面的示例在多个运行时中使用同一个 `Person` Schema。无论使用哪种语言,都需要启用 xlang 模式,并用相同的 ID 或相同的全限定名称注册类型。 + ### Java +Java 的 xlang 用法可以看作 JVM 服务中的基准模式。启用 `Language.XLANG` 后,用稳定的 ID 或名称注册类型,并确保所有对端语言都使用相同的映射关系。 + ```java -import com.google.common.collect.ImmutableMap; -import io.fory.*; +import org.apache.fory.*; +import org.apache.fory.config.*; -import java.util.Map; +public class XlangExample { + public record Person(String name, int age) {} -public class ReferenceExample { - public static class SomeClass { - SomeClass f1; - Map<String, String> f2; - Map<String, String> f3; - } + public static void main(String[] args) { + Fory fory = Fory.builder() + .withLanguage(Language.XLANG) + .build(); - public static Object createObject() { - SomeClass obj = new SomeClass(); - obj.f1 = obj; - obj.f2 = ImmutableMap.of("k1", "v1", "k2", "v2"); - obj.f3 = obj.f2; - return obj; - } + fory.register(Person.class, 1); + // fory.register(Person.class, "example.Person"); - // mvn exec:java -Dexec.mainClass="io.fory.examples.ReferenceExample" - public static void main(String[] args) { - Fory fory = Fory.builder().withLanguage(Language.XLANG) - .withRefTracking(true).build(); - fory.register(SomeClass.class, "example.SomeClass"); - byte[] bytes = fory.serialize(createObject()); - // bytes can be data serialized by other languages. - System.out.println(fory.deserialize(bytes)); - ; + Person person = new Person("chaokunyang", 28); + byte[] bytes = fory.serialize(person); + Person result = (Person) fory.deserialize(bytes); + System.out.println(result.name() + " " + result.age()); } } ``` -### Python +### Go -```python -from typing import Dict -import pyfory - -class SomeClass: - f1: "SomeClass" - f2: Dict[str, str] - f3: Dict[str, str] - -fory = pyfory.Fory(ref_tracking=True) -fory.register_class(SomeClass, "example.SomeClass") -obj = SomeClass() -obj.f2 = {"k1": "v1", "k2": "v2"} -obj.f1, obj.f3 = obj, obj.f2 -data = fory.serialize(obj) -# bytes can be data serialized by other languages. -print(fory.deserialize(data)) -``` - -### Golangs +Go 通过 `WithXlang(true)` 启用跨语言模式。真正关键的不是 Go 语法本身,而是保证注册的类型身份与其他读写同一载荷的语言完全一致。 ```go package main import ( - "fmt" - forygo "github.com/apache/fory/go/fory" + "fmt" + + "github.com/apache/fory/go/fory" ) +type Person struct { + Name string + Age int32 +} + func main() { - type SomeClass struct { - F1 *SomeClass - F2 map[string]string - F3 map[string]string - } - fory := forygo.NewFory(true) - if err := fory.RegisterTagType("example.SomeClass", SomeClass{}); err != nil { - panic(err) - } - value := &SomeClass{F2: map[string]string{"k1": "v1", "k2": "v2"}} - value.F3 = value.F2 - value.F1 = value - bytes, err := fory.Marshal(value) - if err != nil { - } - var newValue interface{} - // bytes can be data serialized by other languages. - if err := fory.Unmarshal(bytes, &newValue); err != nil { - panic(err) - } - fmt.Println(newValue) + f := fory.New(fory.WithXlang(true)) + if err := f.RegisterStruct(Person{}, 1); err != nil { + panic(err) + } + + person := &Person{Name: "chaokunyang", Age: 28} + data, err := f.Serialize(person) + if err != nil { + panic(err) + } + + var result Person + if err := f.Deserialize(data, &result); err != nil { + panic(err) + } + + fmt.Printf("%s %d\n", result.Name, result.Age) +} +``` + +### Rust + +Rust 同样遵循这套跨语言约定,只是通过派生 trait 和在 `Fory` 实例上显式注册来表达。只要类型 ID 与其他运行时一致,载荷就可以安全地跨语言流转。 + +```rust +use fory::{Fory, ForyObject}; +use std::error::Error; + +#[derive(ForyObject, Debug)] +struct Person { + name: String, + age: i32, +} + +fn main() -> Result<(), Box<dyn Error>> { + let mut fory = Fory::default().xlang(true); + fory.register::<Person>(1)?; + // fory.register_by_name::<Person>("example.Person")?; + + let person = Person { + name: "chaokunyang".to_string(), + age: 28, + }; + let bytes = fory.serialize(&person); + let result: Person = fory.deserialize(&bytes)?; + println!("{} {}", result.name, result.age); + Ok(()) } ``` ### JavaScript -```typescript -import Fory, { Type } from "@apache-fory/fory"; +JavaScript 的跨语言支持是基于 Schema 描述的。它不是注册类,而是通过 `Type.object(...)` 描述载荷结构,再使用返回的序列化器来编码和解码数据。 + +```javascript +import Fory, { Type } from "@apache-fory/core"; /** - * @apache-fory/hps use v8's fast-calls-api that can be called directly by jit, ensure that the version of Node is 20 or above. - * Experimental feature, installation success cannot be guaranteed at this moment - * If you are unable to install the module, replace it with `const hps = null;` - **/ + * `@apache-fory/hps` 会通过 JIT 直接使用 V8 fast calls。 + * 启用时请使用 Node.js 20+。 + * 如果安装失败,请将它替换为 `const hps = null;`。 + */ import hps from "@apache-fory/hps"; -// Now we describe data structures using JSON, but in the future, we will use more ways. -const description = Type.object("example.foo", { - foo: Type.string(), +const description = Type.object("example.Person", { + name: Type.string(), + age: Type.int32(), }); + const fory = new Fory({ hps }); const { serialize, deserialize } = fory.registerSerializer(description); -const input = serialize({ foo: "hello fory" }); -const result = deserialize(input); + +const payload = serialize({ name: "chaokunyang", age: 28 }); +const result = deserialize(payload); console.log(result); ``` -### Rust +### C# -```rust -use fory::{from_buffer, to_buffer, Fory}; +C# 的跨语言代码看起来与原生模式很接近,但运行时需要显式启用 xlang 和 compatible 模式。与此同时,仍然必须与 Java、Go、Swift、Rust 等对端使用相同的类型 ID 或 namespace/name 映射。 -#[derive(Fory, Debug, PartialEq)] -#[tag("example.foo")] -struct Animal { - name: String, - category: String, +```csharp +using Apache.Fory; + +[ForyObject] +public sealed class Person +{ + public string Name { get; set; } = string.Empty; + public int Age { get; set; } } -#[derive(Fory, Debug, PartialEq)] -#[tag("example.bar")] -struct Person { - name: String, - age: u32, - pets: Vec<Animal>, -} - -fn main() { - let penson = Person { - name: "hello".to_string(), - age: 12, - pets: vec![ - Animal { - name: "world1".to_string(), - category: "cat".to_string(), - }, - Animal { - name: "world2".to_string(), - category: "dog".to_string(), - }, - ], - }; - let bin = to_buffer(&penson); - let obj: Person = from_buffer(&bin).expect("should success"); - assert_eq!(obj, penson); +Fory fory = Fory.Builder() + .Xlang(true) + .Compatible(true) + .Build(); + +fory.Register<Person>(1); + +Person person = new() { Name = "chaokunyang", Age = 28 }; +byte[] payload = fory.Serialize(person); +Person result = fory.Deserialize<Person>(payload); + +Console.WriteLine($"{result.Name} {result.Age}"); +``` + +### Swift + +Swift 的跨语言序列化仍然使用与原生模式相同的 `@ForyObject` 模型风格,只是在创建运行时时要传入 `xlang: true`。要实现互操作,稳定的注册 ID 仍然是最核心的要求。 + +```swift +import Fory + +@ForyObject +struct Person: Equatable { + var name: String = "" + var age: Int32 = 0 +} + +let fory = Fory(xlang: true, trackRef: false, compatible: true) +fory.register(Person.self, id: 1) + +let person = Person(name: "chaokunyang", age: 28) +let data = try fory.serialize(person) +let result: Person = try fory.deserialize(data) + +print("\(result.name) \(result.age)") +``` + +### 要点 + +- 在每个运行时中都显式启用 xlang 模式,例如 `Language.XLANG`、`WithXlang(true)`、`Xlang(true)`、`Fory(xlang: true, ...)` 等。 +- 在所有语言中使用**一致的 ID 或名称**注册类型。 +- 基于 ID 的注册更紧凑、速度更快,但需要集中协调以避免冲突。 +- 基于名称的注册更容易在团队间管理,但载荷会稍大一些。 +- 只使用具备跨语言映射的类型,详见 [Type Mapping](../specification/xlang_type_mapping.md)。 + +关于跨语言场景中的循环引用、共享引用和多态示例,请参见: + +- [跨语言序列化指南](../guide/xlang/index.md) +- [Go 指南 - 跨语言](../guide/go/cross-language.md) +- [C# 指南 - 跨语言](../guide/csharp/cross-language.md) +- [Swift 指南 - 跨语言](../guide/swift/cross-language.md) + +## Row Format 编码 + +Row format 提供零拷贝随机访问能力,非常适合分析型负载和数据处理流水线。 + +### Java + +```java +import org.apache.fory.format.*; +import java.util.*; +import java.util.stream.*; + +public class Bar { + String f1; + List<Long> f2; +} + +public class Foo { + int f1; + List<Integer> f2; + Map<String, Integer> f3; + List<Bar> f4; } + +RowEncoder<Foo> encoder = Encoders.bean(Foo.class); +Foo foo = new Foo(); +foo.f1 = 10; +foo.f2 = IntStream.range(0, 1000000).boxed().collect(Collectors.toList()); +foo.f3 = IntStream.range(0, 1000000).boxed().collect(Collectors.toMap(i -> "k"+i, i -> i)); + +List<Bar> bars = new ArrayList<>(1000000); +for (int i = 0; i < 1000000; i++) { + Bar bar = new Bar(); + bar.f1 = "s" + i; + bar.f2 = LongStream.range(0, 10).boxed().collect(Collectors.toList()); + bars.add(bar); +} +foo.f4 = bars; + +// 序列化为 row format(可被 Python 以零拷贝方式读取) +BinaryRow binaryRow = encoder.toRow(foo); + +// 反序列化整个对象 +Foo newFoo = encoder.fromRow(binaryRow); + +// 不做完整反序列化,直接零拷贝访问嵌套字段 +BinaryArray binaryArray2 = binaryRow.getArray(1); // 访问 f2 字段 +BinaryArray binaryArray4 = binaryRow.getArray(3); // 访问 f4 字段 +BinaryRow barStruct = binaryArray4.getStruct(10); // 访问第 11 个 Bar 元素 +long value = barStruct.getArray(1).getInt64(5); // 访问嵌套值 + +// 部分反序列化 +RowEncoder<Bar> barEncoder = Encoders.bean(Bar.class); +Bar newBar = barEncoder.fromRow(barStruct); +Bar newBar2 = barEncoder.fromRow(binaryArray4.getStruct(20)); ``` + +### Python + +```python +from dataclasses import dataclass +from typing import List, Dict +import pyarrow as pa +import pyfory + +@dataclass +class Bar: + f1: str + f2: List[pa.int64] + +@dataclass +class Foo: + f1: pa.int32 + f2: List[pa.int32] + f3: Dict[str, pa.int32] + f4: List[Bar] + +encoder = pyfory.encoder(Foo) +foo = Foo( + f1=10, + f2=list(range(1000_000)), + f3={f"k{i}": i for i in range(1000_000)}, + f4=[Bar(f1=f"s{i}", f2=list(range(10))) for i in range(1000_000)] +) + +# 序列化为 row format +binary: bytes = encoder.to_row(foo).to_bytes() + +# 无需完整反序列化即可零拷贝随机访问 +foo_row = pyfory.RowData(encoder.schema, binary) +print(foo_row.f2[100000]) # 直接访问元素 +print(foo_row.f4[100000].f1) # 访问嵌套字段 +print(foo_row.f4[200000].f2[5]) # 访问更深层的嵌套字段 +``` + +更多 row format 细节请参见 [Java Row Format 指南](../guide/java/row-format.md) 或 [Python Row Format 指南](../guide/python/row-format.md)。 --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
