JSON: Json values
Also known as: dynamic type any unknown type duck typing schemaless untyped object dict mixed int float parse api response bigint decimal exact digits big number precision 0.1 lossless
● Intermediate4 min
A Json value holds JSON whose shape is known only while the program runs. It is a union of six cases, one for each kind of JSON value.
type Json = Null |
Boolean(value: Bool) |
Number(digits: String) |
Text(value: String) |
Array(items: [Json]) |
Object(fields: [String: Json])Being a union, match sees every case:
use std.json
fn main() ! Error {
const text = "[1, 2.5, \"three\", true, null, [4]]"
const items = try json.parse(text)
for item in items.list() ?? [] {
match item {
Json.Number(digits) => print("number {digits}"),
Json.Text(s) => print("text {s}"),
Json.Boolean(b) => print("true or false: {b}"),
Json.Null => print("nothing"),
_ => print("a list or an object"),
}
}
}The program ran and printed:
kavach run unknown-json.kav
number 1number 2.5text threetrue or false: truenothinga list or an object
Every method
| Method | Gives |
|---|---|
text() | String?: the text of a Text |
int() | Int?: a Number written without a fraction or exponent that fits Int |
bigint() | BigInt?: a Number written without a fraction or exponent, of any size |
float() | Float?: a Number, as the nearest Float; none past Float's range |
decimal() | Decimal?: a Number, exactly |
bool() | Bool?: the value of a Boolean |
list() | [Json]?: the items of an Array |
object() | [String: Json]?: the fields of an Object |
is_null() | Bool: whether it is Null |
len() | Int: the items of an Array or fields of an Object, otherwise 0 |
Numbers keep their digits
A Number keeps the digits it was written with, exactly, so no number is changed by reading it and writing it out again. Each method reads it as the type you need, and gives none when it doesn't fit:
use std.json
fn main() ! Error {
const doc = try json.parse("\{\"id\": 12345678901234567890, \"price\": 0.1}")
print(doc["id"].bigint())
print(doc["id"].int())
print(doc["price"].decimal())
print(json.stringify(doc))
}The program ran and printed:
kavach run exact-numbers.kav
12345678901234567890none0.1{"id":12345678901234567890,"price":0.1}
- The id is too big for
Int, so.int()givesnone;.bigint()takes any size. .decimal()reads0.1exactly, where aFloatholds only the nearest number to it.- Written out again, both are the same digits that came in.
.float() reads any number, whole or not; "free" isn't a number, so it adds 0.0:
use std.json
fn main() ! Error {
const prices = try json.parse("[10, 2.5, \"free\", 7]")
let total = 0.0
for p in prices.list() ?? [] {
total += p.float() ?? 0.0
}
print(total)
}The program ran and printed:
kavach run unknown-numbers.kav
19.5Parsing takes a number of any size. A number whose exponent puts it beyond 10^10_000, or below 10^-10_000, is out of range for .decimal() and .bigint() too, so a short text can't make a huge value:
use std.json
fn main() ! Error {
const doc = try json.parse("[1e999999999]")
print(doc[0].decimal())
print(json.stringify(doc))
}The program ran and printed:
kavach run huge.kav
none[1e999999999]
JSON's null is the case Null. Kavach itself has no null: see Data Types for how it meets none.