# 运限对象 (/zh/docs/rust/horoscope)

六个运限层级的数据结构、整层取回的三个列表，以及不必再传星盘的宫位查询方法。



运限把本命盘投影到某个时间点上。同一张盘，不同年份看到的宫位分布不同——
这正是「大限走到哪一宫」的意思。

```rust
let h = chart.horoscope("2025-6-1", 0)?;
```

`HoroscopeRef` 持有发起它的那张本命盘，因此所有查询方法都不必再把星盘传进去。

<Callout type="info">
  本页示例统一用 `Language::ZhCN` 的本命盘，因此输出里的展示值都是中文。
</Callout>

## HoroscopeData [#horoscopedata]

`HoroscopeRef` 经 `Deref` 得到 `HoroscopeData`，它有八个字段：两个日期串与六个层级。

| 字段           | 类型              | 说明           |
| ------------ | --------------- | ------------ |
| `solar_date` | `String`        | 目标公历日期，与入参一致 |
| `lunar_date` | `String`        | 目标日期的农历中文写法  |
| `decadal`    | `HoroscopeItem` | 大限           |
| `age`        | `AgeItem`       | 小限           |
| `yearly`     | `YearlyItem`    | 流年           |
| `monthly`    | `HoroscopeItem` | 流月           |
| `daily`      | `HoroscopeItem` | 流日           |
| `hourly`     | `HoroscopeItem` | 流时           |

<Callout type="info">
  `solar_date` 是**目标日期**不是出生日期；出生日期在本命盘上，用 `h.astrolabe().solar_date` 取。
</Callout>

## 六个层级 [#六个层级]

| 字段        | 类型              | 跨度  | 说明            |
| --------- | --------------- | --- | ------------- |
| `decadal` | `HoroscopeItem` | 十年  | 大限。未起运的幼年期为童限 |
| `age`     | `AgeItem`       | 一年  | 小限。按虚岁逐年走一宫   |
| `yearly`  | `YearlyItem`    | 一年  | 流年。按流年干支定宫    |
| `monthly` | `HoroscopeItem` | 一月  | 流月            |
| `daily`   | `HoroscopeItem` | 一日  | 流日            |
| `hourly`  | `HoroscopeItem` | 一时辰 | 流时            |

<Callout type="info" title="小限与流年的区别">
  两者都是一年一走，但起法不同：小限从生年地支起、按虚岁顺推，
  流年直接看那一年的干支落在哪一宫。两条线互相独立，斗数里通常并看。
</Callout>

### HoroscopeItem [#horoscopeitem]

| 字段               | 类型                       | 说明                                                               |
| ---------------- | ------------------------ | ---------------------------------------------------------------- |
| `index`          | `usize`                  | 该层级落在哪一宫（宫位索引）                                                   |
| `name`           | `String`                 | 层级显示名，按输出语言翻译                                                    |
| `name_key`       | `HoroscopeName`          | 层级标识；大限层未起运时为 `Childhood`（童限），与 `Decadal` 是不同的解盘语义，判断层级用它、不要比对译文 |
| `heavenly_stem`  | `HeavenlyStem`           | 该层级的天干，决定它飞出的四化                                                  |
| `earthly_branch` | `EarthlyBranch`          | 该层级的地支                                                           |
| `palace_names`   | `Vec<Palace>`            | 以该层级所在宫为命宫重推的十二宫名，按宫位索引排列                                        |
| `mutagen`        | `Vec<StarKey>`           | 该层级天干引发的四化星，顺序为禄权科忌                                              |
| `stars`          | `Option<Vec<Vec<Star>>>` | 该层级的流耀分布；无流耀的层级为 `None`                                          |

`age` 与 `yearly` 不是 `HoroscopeItem` 本身，而是各自多带一项数据的包装：

```rust
pub struct AgeItem {
    pub base: HoroscopeItem,
    pub nominal_age: u32,          // 该日期对应的虚岁
}

pub struct YearlyItem {
    pub base: HoroscopeItem,
    pub yearly_dec_star: YearlyDecStar,
}

pub struct YearlyDecStar {
    pub jiangqian12: Vec<StarKey>, // 流年将前十二神，按宫位索引排列
    pub suiqian12: Vec<StarKey>,   // 流年岁前十二神，按宫位索引排列
}
```

`AgeItem` 与 `YearlyItem` 都实现 `Deref<Target = HoroscopeItem>`，通用字段直接读：
`h.yearly.heavenly_stem`、`h.age.index`；需要整个 `HoroscopeItem` 时取 `.base`。
四个类型都在 crate 根重导出。

**示例**

```rust
let h = chart.horoscope("2025-6-1", 0)?;

for item in [&h.decadal, &h.monthly, &h.daily, &h.hourly] {
    println!("{} 落在宫位 {} 干支 {}{}", item.name, item.index,
        translate_heavenly_stem(item.heavenly_stem, Language::ZhCN),
        translate_earthly_branch(item.earthly_branch, Language::ZhCN));
}
println!("小限虚岁 {}", h.age.nominal_age);
```

**输出**

```text
大限 落在宫位 2 干支 庚辰
流月 落在宫位 3 干支 壬午
流日 落在宫位 8 干支 辛丑
流时 落在宫位 8 干支 戊子
小限虚岁 26
```

***

## 三个列表 [#三个列表]

`decadal_list` / `yearly_list` / `monthly_list` 是 `Astrolabe` 上的方法，不在运限对象上：
它们一次取回整层的运限项，省去按日期逐个调 `horoscope` 再自己拼。
每项都在通用的 `HoroscopeItem` 之外多带该层的时间坐标：

```rust
pub struct DecadalHoroscope {
    pub base: HoroscopeItem,
    pub palace_name: Palace,     // 该大限所在的本命宫名
    pub age_range: (u32, u32),   // 起止虚岁，含两端
    pub year_range: (i64, i64),  // 起止农历年份，含两端
}

pub struct YearlyHoroscope {
    pub base: HoroscopeItem,
    pub age: u32,                // 该流年对应的虚岁
    pub year: i64,               // 农历年份
}

pub struct MonthlyHoroscope {
    pub base: HoroscopeItem,
    pub age: u32,                // 该流月对应的虚岁
    pub year: i64,               // 农历年份
    pub month: u32,              // 农历月份，正月为 1；闰月与同号常规月的 month 相同
    pub is_leap_month: bool,     // 该项是否闰月
    pub part: MonthPart,         // Normal 整月 / First 闰月前半 / Second 闰月后半
    pub day_range: (u32, u32),   // 该段覆盖的农历日，含两端
}
```

三者都实现 `Deref<Target = HoroscopeItem>`，通用字段直接读（`d.heavenly_stem`、`d.palace_names`），
需要整个 `HoroscopeItem` 时取 `.base`。四个类型与 `MonthPart` 都在 crate 根重导出。

<Callout type="info" title="列表里的运限按时柱地支起">
  三个列表的每一项都以**时柱地支**对应的时辰计算，而不是排盘时传入的 `time_index`。
  两者只在晚子时不同：入参 12 的盘，时柱地支是子，列表按时辰 0 起运限。
</Callout>

***

## decadal\_list [#decadal_list]

**用途**　一次取回本盘十二个大限，按起运先后排列。

**斗数含义**　大限十年一步，从命宫或其他起限宫顺逆行走十二宫。
把整条线摊平看，才知道某一段人生落在哪一宫、对应哪十年。

**签名**

```rust
pub fn decadal_list(&self) -> Vec<DecadalHoroscope>
```

**返回值**　定长 12 项，第 0 项是第一个大限。顺序按起运虚岁排，
与宫位索引顺序无关（大限顺行逆行取决于阴阳男女）。

**示例**

```rust
let zh = Language::ZhCN;

for d in chart.decadal_list().iter().take(3) {
    println!("{} {}{} {}-{} {}-{}",
        translate_palace(d.palace_name, zh),
        translate_heavenly_stem(d.heavenly_stem, zh),
        translate_earthly_branch(d.earthly_branch, zh),
        d.age_range.0, d.age_range.1, d.year_range.0, d.year_range.1);
}
println!("{}", chart.decadal_list().len());
```

**输出**

```text
命宫 壬午 3-12 2002-2011
兄弟 辛巳 13-22 2012-2021
夫妻 庚辰 23-32 2022-2031
12
```

这张盘三岁起运，第一个大限落在命宫。

**边界与陷阱**

<Callout type="info" title="列表里没有童限">
  起运之前的那几年是童限，只有按具体日期查 `horoscope` 才会出现（`name_key` 为 `Childhood`）。
  `decadal_list` 列的是十二个大限本身，每项的 `name_key` 恒为 `Decadal`。
</Callout>

***

## yearly\_list [#yearly_list]

**用途**　取一个大限内的全部流年。

**斗数含义**　定了大限再逐年细看，是斗数常规的推运顺序。
一个大限十年，对应的就是这十个流年。

**签名**

```rust
pub fn yearly_list(&self, target: impl Into<DecadalTarget>) -> Result<Vec<YearlyHoroscope>, IztroError>
```

**参数**

| 参数       | 类型                         | 必填 | 默认 | 说明                                         |
| -------- | -------------------------- | -- | -- | ------------------------------------------ |
| `target` | `impl Into<DecadalTarget>` | 是  | —  | 大限序号（`usize`，0 为第一个大限）或该限所在的本命宫名（`Palace`） |

```rust
pub enum DecadalTarget {
    Ordinal(usize),  // 起运先后序号
    Name(Palace),    // 该大限所在的本命宫名
}
```

两种写法定位到同一个大限时结果完全相同，选哪个取决于手上已有什么。

**返回值**　`Result<Vec<YearlyHoroscope>, IztroError>`，10 项，按虚岁先后排列。
序号越界或宫名定位不到时返回 `Err`。

**示例**

```rust
let zh = Language::ZhCN;
let list = chart.yearly_list(2usize)?;

for y in list.iter().take(3) {
    println!("{} {} {}{} -> {}", y.age, y.year,
        translate_heavenly_stem(y.heavenly_stem, zh),
        translate_earthly_branch(y.earthly_branch, zh), y.index);
}
println!("{} {}", list.len(), chart.yearly_list(Palace::Spouse)?.len());
```

**输出**

```text
23 2022 壬寅 -> 0
24 2023 癸卯 -> 1
25 2024 甲辰 -> 2
10 10
```

第 2 个大限落在夫妻宫，因此 `yearly_list(2)` 与 `yearly_list(Palace::Spouse)` 是同一个大限。

**边界与陷阱**

<Callout type="warn" title="没有默认大限">
  两种定位必须给一个，没有「不传就取当前大限」的行为——静默取一个默认值会把漏传
  变成看起来成功的错答案。
</Callout>

***

## monthly\_list [#monthly_list]

**用途**　取一个农历年的全部流月。

**斗数含义**　流月是流年之下的一层，逐月推移。闰月怎么算是一个流派分歧点，
因此拆不拆由调用方定。

**签名**

```rust
pub fn monthly_list(&self, year: i64, fix_leap: bool) -> Result<Vec<MonthlyHoroscope>, IztroError>
```

**参数**

| 参数         | 类型     | 必填 | 默认 | 说明           |
| ---------- | ------ | -- | -- | ------------ |
| `year`     | `i64`  | 是  | —  | 农历年份         |
| `fix_leap` | `bool` | 是  | —  | 闰月是否拆成前后半月两项 |

**返回值**　`Result<Vec<MonthlyHoroscope>, IztroError>`，长度取决于该年有无闰月与 `fix_leap`：

| 该农历年 | `fix_leap` | 项数 | 闰月怎么排                                  |
| ---- | ---------- | -- | -------------------------------------- |
| 无闰月  | 任意         | 12 | —                                      |
| 有闰月  | `true`     | 14 | 闰月拆成 `First`（初一至十五）与 `Second`（十六至月末）两项 |
| 有闰月  | `false`    | 13 | 闰月整月一项，`part` 为 `Normal`               |

闰月排在同月号的常规月之后。每项按该段首日算出（后半段取十六）。

**示例**

```rust
let zh = Language::ZhCN;
let list = chart.monthly_list(2020, true)?;

println!("{}", list.len());
for m in list.iter().skip(3).take(4) {
    println!("{} {} {} {}-{} {}{}", m.month, m.is_leap_month, m.part.as_key(),
        m.day_range.0, m.day_range.1,
        translate_heavenly_stem(m.heavenly_stem, zh),
        translate_earthly_branch(m.earthly_branch, zh));
}
println!("{} {}", chart.monthly_list(2020, false)?.len(), chart.monthly_list(2021, true)?.len());
```

**输出**

```text
14
4 false normal 1-30 辛巳
4 true first 1-15 辛巳
4 true second 16-29 壬午
5 false normal 1-30 壬午
13 12
```

农历 2020 年有闰四月。拆开之后，闰四月前半与四月同干支（辛巳），后半跟五月同干支（壬午）
——这正是「闰月下半月算下一个月」的意思。农历 2021 年无闰月，恒为 12 项。

**边界与陷阱**

<Callout type="warn" title="这个 fix_leap 与排盘的 fix_leap 无关">
  排盘入口那个 `fix_leap` 决定闰月出生的人下半月按下个月安星，改的是本命盘布局；
  这里这个只决定本列表拆不拆闰月。两者可以取不同的值，互不影响。
</Callout>

<Callout type="info" title="闰月与常规月的 month 相同">
  闰四月的 `month` 也是 `4`，靠 `is_leap_month` 区分。按 `month` 去重会把闰月弄丢。
</Callout>

***

## age\_palace [#age_palace]

**用途**　取小限当年所在的宫。

**斗数含义**　小限是逐年推移的一条线，落在哪一宫就以那宫为该年重点。

**签名**

```rust
pub fn age_palace(&self) -> PalaceRef<'a>
```

**返回值**　`PalaceRef`——本命盘上的宫位，必然存在。

**示例**

```rust
let h = chart.horoscope("2025-6-1", 0)?;
println!("{}", translate_palace(h.age_palace().name, Language::ZhCN));
```

**输出**

```text
田宅
```

***

## palace [#palace]

**用途**　取某个运限层级下、按该层级重推的十二宫中的某一宫。

**斗数含义**　大限走到某宫后，以那一宫为「大限命宫」重排十二宫。
「大限的夫妻宫」问的就是这套重排后的宫位，与本命夫妻宫通常不是同一宫。

**签名**

```rust
pub fn palace(&self, name: Palace, scope: Scope) -> Option<PalaceRef<'a>>
```

**参数**

| 参数      | 类型       | 必填 | 默认 | 说明          |
| ------- | -------- | -- | -- | ----------- |
| `name`  | `Palace` | 是  | —  | 要取的宫名       |
| `scope` | `Scope`  | 是  | —  | 在哪个层级的十二宫里找 |

**返回值**　`Option<PalaceRef<'a>>`——本命盘上的宫位（同一格宫位在不同层级有不同宫名）。
层级为 `Origin` 时即本命十二宫。

**示例**

```rust
let zh = Language::ZhCN;
let h = chart.horoscope("2025-6-1", 0)?;

println!("大限命宫落在本命的 {}",
    translate_palace(h.palace(Palace::Soul, Scope::Decadal).unwrap().name, zh));
println!("本命命宫是 {}",
    translate_palace(h.palace(Palace::Soul, Scope::Origin).unwrap().name, zh));
```

**输出**

```text
大限命宫落在本命的 夫妻
本命命宫是 命宫
```

**边界与陷阱**

<Callout type="info" title="返回的是本命盘上的那一格">
  `palace(Soul, Decadal)` 返回的宫位对象上，`name` 仍是**本命宫名**（例中的夫妻），
  因为它就是本命盘上的那一格。要看该格在大限层级叫什么，查 `h.decadal.palace_names[index]`。
</Callout>

***

## surround\_palaces [#surround_palaces]

**用途**　取某个运限层级下某宫的三方四正。

**签名**

```rust
pub fn surround_palaces(&self, name: Palace, scope: Scope) -> Option<SurroundedPalaces<'a>>
```

**参数**　同 `palace`。

**返回值**　`Option<SurroundedPalaces<'a>>`，判断方法见[三方四正](/zh/docs/rust/surpalaces)。

**示例**

```rust
let h = chart.horoscope("2025-6-1", 0)?;
let sp = h.surround_palaces(Palace::Wealth, Scope::Yearly).unwrap();

println!("流年财帛的三方四正以本命 {} 为本宫", translate_palace(sp.target.name, Language::ZhCN));
```

**输出**

```text
流年财帛的三方四正以本命 疾厄 为本宫
```

***

## has\_horoscope\_stars / has\_one\_of\_horoscope\_stars / not\_have\_horoscope\_stars [#has_horoscope_stars--has_one_of_horoscope_stars--not_have_horoscope_stars]

**用途**　判断某层级某宫里有没有指定的流耀。

**斗数含义**　流耀是随运限层级产生的一组星：魁钺昌曲禄羊陀马鸾喜。
它们在不同层级有不同名字——大限层级叫运魁、运钺，流年层级叫流魁、流钺，
含义相同但作用于各自的时间跨度。

**签名**

```rust
pub fn has_horoscope_stars(&self, name: Palace, scope: Scope, stars: &[StarKey]) -> bool
pub fn has_one_of_horoscope_stars(&self, name: Palace, scope: Scope, stars: &[StarKey]) -> bool
pub fn not_have_horoscope_stars(&self, name: Palace, scope: Scope, stars: &[StarKey]) -> bool
```

**参数**

| 参数      | 类型           | 必填 | 默认 | 说明            |
| ------- | ------------ | -- | -- | ------------- |
| `name`  | `Palace`     | 是  | —  | 该层级下的宫名       |
| `scope` | `Scope`      | 是  | —  | 运限层级          |
| `stars` | `&[StarKey]` | 是  | —  | 流耀标识，须用该层级的名字 |

**返回值**

| 方法                           | 语义    |
| ---------------------------- | ----- |
| `has_horoscope_stars`        | 每一颗都在 |
| `has_one_of_horoscope_stars` | 至少一颗在 |
| `not_have_horoscope_stars`   | 一颗都不在 |

**示例**

```rust
use x_iztro::StarKey::*;

let h = chart.horoscope("2025-6-1", 0)?;

println!("{}", h.has_horoscope_stars(Palace::Soul, Scope::Decadal, &[Yunlu]));
println!("{}", h.has_one_of_horoscope_stars(Palace::Soul, Scope::Decadal, &[Yunlu, Yunyang]));
println!("{}", h.not_have_horoscope_stars(Palace::Soul, Scope::Decadal, &[Yuntuo]));
```

**输出**

```text
false
false
true
```

**边界与陷阱**

<Accordions>
  <Accordion title="scope 只决定查哪一宫，不决定查哪些星">
    三个方法用 `scope` + `name` 定位到本命盘上的某一格，
    但要比对的星耀集合恒为**大限流耀与流年流耀的并集**，与 `scope` 无关。

    因此 `scope` 传 `Monthly` 时，查的是「流月某宫这一格里有没有大限或流年的流耀」，
    而不是流月自己的流耀——流月、流日、流时三层的流耀不参与这里的比对。
    要按层级取流耀分布，用 `h.monthly.stars` 一类字段，或
    [`get_horoscope_stars`](/zh/docs/rust/star#get_horoscope_stars)。
  </Accordion>

  <Accordion title="流耀标识按层级区分">
    大限流耀叫 `Yunlu`（运禄）、`Yunyang`（运羊）……，流年流耀叫 `Liulu`（流禄）、
    `Liuyang`（流羊）……，两组标识不同名。由于比对集合恒是这两组的并集，
    `Yunlu` 与 `Liulu` 在任何 `scope` 下都查得到，只是落宫不同。
    各层级的标识对照见[安星模块](/zh/docs/rust/star#get_horoscope_stars)。
  </Accordion>

  <Accordion title="scope 传 Origin 时定位到本命宫位">
    `Origin` 走的是本命十二宫，因此仍能定位到宫位；
    只是本命盘上没有流耀，比对的仍是大限与流年的流耀落在那一格的部分。
  </Accordion>
</Accordions>

***

## has\_horoscope\_mutagen [#has_horoscope_mutagen]

**用途**　判断某层级某宫里有没有该层级天干引发的四化。

**斗数含义**　每个运限层级有自己的天干，会像生年干一样化出四颗星。
「大限化禄落在大限财帛」这类判断问的就是这个。

**签名**

```rust
pub fn has_horoscope_mutagen(&self, name: Palace, scope: Scope, mutagen: Mutagen) -> bool
```

**参数**

| 参数        | 类型        | 必填 | 默认 | 说明      |
| --------- | --------- | -- | -- | ------- |
| `name`    | `Palace`  | 是  | —  | 该层级下的宫名 |
| `scope`   | `Scope`   | 是  | —  | 运限层级    |
| `mutagen` | `Mutagen` | 是  | —  | 四化之一    |

**返回值**　`bool`。检查该层级天干化出的那颗星是否落在目标宫的主星或辅星里（不看杂耀）。

**示例**

```rust
let h = chart.horoscope("2025-6-1", 0)?;

println!("{}", h.has_horoscope_mutagen(Palace::Soul, Scope::Decadal, Mutagen::Lu));

// 该层级化出的四颗星本身可直接读
println!("{:?}", h.decadal.mutagen.iter()
    .map(|s| translate_star(*s, Language::ZhCN)).collect::<Vec<_>>());
```

**输出**

```text
false
["太阳", "武曲", "太阴", "天同"]
```

大限干为庚，庚干四化为太阳化禄、武曲化权、太阴化科、天同化忌。

**边界与陷阱**

<Callout type="warn" title="scope 为 Origin 时恒为 false">
  本命层级没有「层级天干」这回事——生年四化已经打在星耀自身的 `mutagen` 字段上。
  `has_horoscope_mutagen(name, Scope::Origin, m)` 因此直接返回 `false`，
  不代表本命盘上没有这个四化。要查本命四化，用宫位的
  [`has_mutagen`](/zh/docs/rust/palace#has_mutagen--not_have_mutagen)。
</Callout>

***

## astrolabe / data / into\_data [#astrolabe--data--into_data]

**用途**　回到本命盘，或取出运限的纯数据。

**签名**

```rust
pub fn astrolabe(&self) -> &'a Astrolabe
pub fn data(&self) -> &HoroscopeData
pub fn into_data(self) -> HoroscopeData
```

**返回值**

| 方法          | 用途                                        |
| ----------- | ----------------------------------------- |
| `astrolabe` | 回到发起这次运限的本命盘                              |
| `data`      | 借用底层数据；视图已实现 `Deref`，通常直接写 `h.decadal` 即可 |
| `into_data` | 取走数据、丢掉对星盘的借用，用于需要 `'static` 生命周期的场合      |

**示例**

```rust
let h = chart.horoscope("2025-6-1", 0)?;

println!("{}", h.astrolabe().solar_date);

let data: HoroscopeData = h.into_data();   // 不再借用 chart
println!("{}", data.solar_date);
```

**输出**

```text
2000-8-16
2025-6-1
```

***

## to\_text [#to_text]

**用途**　运限的语义化文本：面向语言模型与人的完整描述，Markdown 子集。

**签名**

```rust
pub fn to_text(&self) -> String
```

定义在 `HoroscopeRef` 上，按星盘排盘语言输出；要指定语言用自由函数
`text::horoscope_to_text(astrolabe, horoscope, lang)`。

**返回值**　`String`——大限（未起运为童限）、小限、流年、流月、流日、流时各一节，
各层带四化、该层视角的格局与流耀，大限与流年展开十二宫表。
完整格式见[语义化文本](/zh/docs/guide/guides/to-text)。

**示例**

```rust
let h = chart.horoscope("2025-1-1", 0)?;

for line in h.to_text().lines().take(5) {
    println!("{line}");
}
```

**输出**

```text
# 运限 2025-1-1 (二〇二四年腊月初二)

## 大限 · 命宫: 本命夫妻 (庚辰)
- 四化: 太阳化禄→本命子女, 武曲化权→本命财帛, 太阴化科→本命仆役, 天同化忌→本命疾厄
- 格局: 杀破狼 (命宫), 风云际会 (命宫)
```

***

## to\_text\_with [#to_text_with]

**用途**　`to_text` 的同一份文本，按 [`TextOptions`](/zh/docs/rust/astro#textoptions) 附释义：
每层的表或事实之后紧跟该层流耀的释义与该层视角命中格局的释义，跨层去重。
本命星耀的释义不在这里重复，在本命盘的 `to_text_with` 里。

**签名**

```rust
pub fn to_text_with(&self, opts: &TextOptions) -> String
```

**参数**

| 参数     | 类型             | 必填 | 默认 | 说明                                                                                    |
| ------ | -------------- | -- | -- | ------------------------------------------------------------------------------------- |
| `opts` | `&TextOptions` | 是  | —  | 输出选项；`TextOptions::new().knowledge(pack)` 带释义，`TextOptions::default()` 与 `to_text` 等价 |

定义在 `HoroscopeRef` 上，按星盘排盘语言输出；要指定语言用自由函数
`text::horoscope_to_text_with(astrolabe, horoscope, opts, lang)`。
插入位置见[带释义的文本](/zh/docs/guide/guides/to-text#带释义的文本)。

**示例**

```rust
let pack = KnowledgePack::builtin(Language::ZhCN).unwrap();
let h = chart.horoscope("2025-1-1", 0)?;
let text = h.to_text_with(&TextOptions::new().knowledge(pack));

println!("{} {}", h.to_text().chars().count(), text.chars().count());
for line in text.lines().filter(|l| l.starts_with("## ")) {
    println!("{line}");
}
```

**输出**

```text
2457 8458
## 大限 · 命宫: 本命夫妻 (庚辰)
## 小限 · 命宫: 本命官禄 · 虚岁 25
## 流年 · 命宫: 本命夫妻 (甲辰)
## 流月 · 命宫: 本命仆役 (丁丑)
## 流日 · 命宫: 本命迁移 (庚午)
## 流时 · 命宫: 本命迁移 (丙子)
```

***

## to\_dto [#to_dto]

**用途**　把运限数据转成与 JS iztro 字段契约一致的序列化结构。

**签名**

```rust
pub fn to_dto(&self, lang: Language) -> HoroscopeDto
```

**参数**

| 参数     | 类型         | 必填 | 默认 | 说明        |
| ------ | ---------- | -- | -- | --------- |
| `lang` | `Language` | 是  | —  | 译名字段用哪种语言 |

定义在 `HoroscopeData` 上（不是 `HoroscopeRef`）。运限数据本身不记语言，
因此这里要显式传——通常传 `chart.language` 与本命盘保持一致。

**返回值**　`x_iztro::dto::HoroscopeDto`，camelCase 键 + `*Key` 标识。

**示例**

```rust
let h = chart.horoscope("2025-6-1", 0)?;
let json = serde_json::to_string(&h.to_dto(chart.language))?;
let v: serde_json::Value = serde_json::from_str(&json)?;

println!("{} {}", v["solarDate"], v["decadal"]["heavenlyStem"]);
println!("{}", v["age"]["nominalAge"]);
```

**输出**

```text
"2025-6-1" "庚"
26
```
