A struct can carry a field of type Fn, and calling it works with three kinds of receiver: a local variable, a by-value parameter, and a field nested inside another struct. What still does not work is calling the field directly (pais.calcular_impuesto(monto)): the compiler rejects that with NYX1016, so the field has to be bound to a variable first, without annotating its type.
// Campo `Fn` en un struct: ligar el campo a una variable SIN anotar el tipo // y llamar la variable — funciona con el receptor como variable local, // parámetro por valor y campo anidado (también con parámetro puntero, // `c: *Contrato`, no mostrado aquí). Llamar el campo DIRECTO // (`pais.calcular_impuesto(monto)`) sigue sin soportarse (NYX1016): hay que // ligarlo a una variable primero. struct Pais { nombre: String, calcular_impuesto: Fn(float) -> float } struct Region { pais: Pais } fn impuesto_ar(monto: float) -> float { return monto * 0.21 } fn impuesto_uy(monto: float) -> float { return monto * 0.22 } // Receptor: parámetro POR VALOR fn cobrar(p: Pais, monto: float) -> float { let calcular = p.calcular_impuesto // sin anotar return calcular(monto) } fn main() -> int { let ar: Pais = Pais { nombre: "Argentina", calcular_impuesto: impuesto_ar } // Receptor: variable local let f = ar.calcular_impuesto print(ar.nombre + ": " + float_to_string(f(100.0))) print("cobrar(): " + float_to_string(cobrar(ar, 100.0))) // Receptor: campo anidado let uy: Pais = Pais { nombre: "Uruguay", calcular_impuesto: impuesto_uy } let r: Region = Region { pais: uy } let calcular_anidado = r.pais.calcular_impuesto print(r.pais.nombre + ": " + float_to_string(calcular_anidado(100.0))) return 0 }
Argentina: 21.0 cobrar(): 21.0 Uruguay: 22.0
How it works
All three calls follow the same pattern: let calcular = valor.campo_fn followed by calcular(argumentos). f = ar.calcular_impuesto binds the field off a local variable; cobrar does the same off p, a by-value parameter; and calcular_anidado = r.pais.calcular_impuesto walks a struct field nested inside another struct before binding.
None of the three annotates the type of calcular: the compiler infers the full signature (Fn(float) -> float) from the source field, so the indirect call knows which return convention to use. That is exactly what avoids the unsigned-Fn problem — see the HTTP deadline-and-cause recipe for the case where a signature does have to be declared by hand.