Pular para o conteúdo

JSON (std::json)

Nesta página

std::json converte entre valores Zolo e texto JSON. Os mapas #{} viram objetos JSON, arrays viram arrays JSON e primitivos mapeiam diretamente.

Encode (serialização)

json.encode(valor) — alias json.stringify — produz uma string JSON:

Primitivos, mapas e arrays; stringify é o mesmo que encode.

01-encode.zolo
Playground
// Feature: json.encode — serialize a Zolo value to a JSON string

// When to use: send data over HTTP, save to file, structured logs.


use std::json

// Primitive types map 1:1 to JSON.

print(json.encode(42))  // expected: 42

print(json.encode(3.14))  // expected: 3.14

print(json.encode(true))  // expected: true

print(json.encode(nil))  // expected: null

print(json.encode("hello"))  // expected: "hello"


// Map literal becomes a JSON object.

let user = #{name: "Alice", age: 30, active: true}
print(json.encode(user))  // expected: {"name":"Alice", ...}


// Array becomes a JSON array.

const nums = [1, 2, 3, 4, 5]
print(json.encode(nums))  // expected: [1,2,3,4,5]


// `stringify` is an alias for `encode` (JS-style).

print(json.stringify(#{k: "v"}))  // expected: {"k":"v"}

Decode (desserialização)

json.decode(string) — alias json.parse — converte JSON em valor Zolo. Use strings brutas r#"..."# para evitar a cerimônia de escapar aspas:

Objeto e array decodificados; parse é o mesmo que decode.

02-decode.zolo
Playground
// Feature: json.decode — convert a JSON string to a Zolo value

// When to use: parse API payloads, read JSON config files.

// For inline JSON literals use the tagged literal `json"..."` — it is more

// readable than escaping everything with `\"` and `\{`.


use std::json

// Decode primitives. `json.decode` takes a STRING; the tagged

// literal `json"..."` is itself a parsed Zolo value (table), so use

// raw strings (`r#"..."#`) as input here to avoid escape ceremony.

print(json.decode("42"))  // expected: 42

print(json.decode(r#""hi""#))  // expected: hi

print(json.decode("true"))  // expected: true

print(json.decode("null"))  // expected: nil


// Decode object -> map.

let obj = json.decode(r#"{"name":"Bob","age":25}"#)
print(obj["name"])  // expected: Bob

print(obj["age"])  // expected: 25


// Decode array. Arrays are 0-indexed via `[]` in Zolo.

let arr = json.decode("[10, 20, 30]")
print(arr[0])  // expected: 10

print(arr[2])  // expected: 30


// `parse` is an alias for `decode` (JS-style).

let parsed = json.parse(r#"{"ok":true}"#)
print(parsed["ok"])  // expected: true


// Tip: when you have inline JSON, the tagged literal `json"..."`

// returns a Zolo value directly — no decode call needed.

Estruturas Aninhadas

Objetos dentro de arrays e vice-versa — round-trip sem perda:

Encode → decode preserva hierarquia de mapas e arrays.

03-nested.zolo
Playground
// Feature: json — nested values (objects inside arrays and vice versa)

// When to use: complex JSON documents from REST APIs.


use std::json

// Object that contains an array.

let post = #{
  id: 1,
  title: "Hello",
  tags: ["zolo", "json", "stdlib"],
  author: #{name: "Alice", email: "alice@example.com"},
}

let encoded = json.encode(post)
print(encoded)

// Round-trip: encode -> decode -> same structure.

let decoded = json.decode(encoded)
print(decoded["title"])  // expected: Hello

print(decoded["tags"][1])  // expected: json

print(decoded["author"]["name"])  // expected: Alice


// Array of objects.

let users = [
  #{name: "Alice", age: 30},
  #{name: "Bob", age: 25},
]
let raw = json.encode(users)
let back = json.decode(raw)
print(back[0]["name"])  // expected: Alice

print(back[1]["age"])  // expected: 25

Tratamento de Erros

json.decode devolve (nil, msg_erro) quando a entrada é inválida. O padrão idiomático é envolver numa função que retorna Result:

Destructuring duplo let v, e = json.decode(s) para checar falhas.

04-error-handling.zolo
Playground
// Feature: json.decode — error handling

// When to use: parsing payloads with no guarantee they are valid JSON.

// json.decode returns (nil, err_msg) on failure — standard return protocol.


use std::Result
use std::json

// json.decode takes a STRING — use raw strings to avoid escapes.

let valid = json.decode(r#"{"ok":true}"#)
print(valid["ok"])  // expected: true


// Invalid input -> value is nil, err carries a message.

let bad, err = json.decode("garbage payload")
print(bad)  // expected: nil

print(err != nil)  // expected: true


// Idiomatic pattern: wrap in a Result.

fn safe_parse(s: str) {
  let v, e = json.decode(s)
  if e != nil { return Result.Err(e) }
  return Result.Ok(v)
}

let r1 = safe_parse("42")
let r2 = safe_parse("not valid json text")
print(r1.is_ok())  // expected: true

print(r2.is_err())  // expected: true

Literal json"..."

O literal marcado json#"..."# é resolvido em tempo de compilação — sem chamada a decode em tempo de execução, sem escapes:

Defaults de configuração como literal JSON compilado.

05-tagged-template.zolo
Playground
// Feature: `json"..."` — JSON literal as a tagged template

// Syntax: the template body is parsed as JSON at compile time and

// emitted as a Map. No runtime decode call, no escaping ceremony.

// When to use: defaults / fixtures / inline configs that are easier

// to read as JSON than as `#{...}` map literals.


use std::Map

let defaults = json#"{ "port": 8080, "host": "localhost", "debug": true }"#
print(defaults["port"])
// expected: 8080

print(defaults["host"])
// expected: localhost

print(defaults["debug"])
// expected: true


// For simple inline maps, the `#{...}` map literal is more idiomatic

// than the `json"..."` tagged template — no JSON parsing, just keys.

let cfg = #{
  name: "alice",
  age: 30,
  active: true,
}
print(cfg["name"])  // expected: alice

print(cfg["age"])  // expected: 30

print(cfg["active"])  // expected: true

Path Walk

valor.path("a.b.0.c") navega por um mapa aninhado com segmentos pontilhados; segmentos numéricos indexam arrays:

path e has_path para acessar e verificar chaves profundas.

06-path-walk.zolo
Playground
// Feature: `data.path("a.b.0.c")` — walk a nested map by dotted segments

// Syntax: numeric segments are 0-based array indices; everything else

// is a map key. `data.has_path("a.b")` is the boolean wrapper.

// When to use: pluck a single value out of a deeply-nested config or

// JSON response without writing a chain of `["a"]["b"]` indexes.


let data = #{
    "users": [
        #{ "name": "alice", "role": "admin" },
        #{ "name": "bob",   "role": "dev" },
    ],
    "config": #{
        "port": 8080,
        "debug": true,
    },
}

print(data.path("config.port"))      // expected: 8080

print(data.path("config.debug"))     // expected: true

print(data.path("users.0.name"))     // expected: alice

print(data.path("users.1.role"))     // expected: dev


// `has_path` returns whether the value exists.

print(data.has_path("config.port"))     // expected: true

print(data.has_path("config.missing"))  // expected: false

Valores Ausentes via Path

path retorna nil para segmentos inexistentes; has_path distingue "ausente" de "presente mas falso":

has_path("config.debug") é true mesmo quando o valor é false.

07-path-missing.zolo
Playground
// Feature: `path` and `has_path` semantics for missing / falsy values

// Rules:

//   - missing segment → `nil`

//   - walking through a non-table → `nil`

//   - `has_path` returns `false` for missing, `true` for present-but-falsy

// When to use: distinguish "not provided" from "set to false" in

// settings / feature flags / JSON inputs.


let data = #{
    "config": #{
        "port": 8080,
        "debug": false,
    },
}

// Missing segment → nil.

print(data.path("config.missing"))
// expected: nil


print(data.path("nope.also.missing"))
// expected: nil


// `has_path` is the boolean wrapper.

print(data.has_path("config.missing"))
// expected: false


// A `false` *value* is still present.

print(data.has_path("config.debug"))
// expected: true


// Walking past a leaf (port is an int) gives nil.

print(data.path("config.port.deeper"))
// expected: nil

Interop com Schemas

Toda declaração schema ganha from_json(str) -> Result e to_json() -> str automaticamente:

Point.from_json valida + decodifica; p.to_json() serializa a instância.

08-schema-interop.zolo
Playground
// Feature: `Schema.from_json` / `instance.to_json()` round-trip

// Syntax: every `schema` declaration auto-generates `from_json(str)`

// (decodes + parses, returns Result) and `instance.to_json()` (encodes

// via to_map + json.encode).

// When to use: end-to-end validation of JSON requests/responses.

// Combines the validation in `features/23-schemas/` with

// `json.encode` / `json.decode`.


use std::Result
use std::json

schema Point {
    x: int,
    y: int,
}

// from_json: decode JSON, then run through Schema.parse so all

// `where` constraints fire. Returns Result.

let raw = "\{ \"x\": 3, \"y\": 4 \}"
match Point.from_json(raw) {
    Result::Ok(p) => {
        print(p.x)   // expected: 3

        print(p.y)   // expected: 4

    },
    Result::Err(e) => print("error: {e}"),
}

// to_json: instance → JSON string. Key order is not stable, but the

// substrings are. (We use `Point.new(...)` here — the factory built

// for every schema.)

let p = Point.new(3, 4)
let s = p.to_json()
print(s.contains("\"x\":3"))   // expected: true

print(s.contains("\"y\":4"))   // expected: true

Buscar no Zolo

9 resultados

enespt-br