与其他编程语言类似,Slint 中的函数是对一段逻辑/代码进行命名、组织和复用的方式。
函数可以作为组件的一部分定义,也可以作为组件内某个元素的一部分定义。 无法声明全局(顶级)函数,也无法在 结构体或枚举中声明函数。同样也不能在其他函数内嵌套定义函数。
声明函数
Slint 中的函数使用 function 关键字进行声明。例如:
export component Example { // ... function my-function(parameter: int) -> string { // Function code goes here return "result"; }}函数可以带有参数,参数在圆括号内声明,格式为 name: type。 这些参数可以在函数体内通过其名称引用。参数按值 传递。
函数也可以返回一个值。返回类型在函数 签名的 -> 之后指定。如果未指定返回类型,则返回类型为 void。return 关键字用于 在函数体内返回所声明类型的表达式。如果一个函数期望 返回一个值但没有显式的 return 语句,那么默认会返回 最后一个语句的值。
函数可以使用 pure 关键字进行标注。 这表示该函数不会产生任何副作用。 更多详细信息可在 Purity 章节找到。
调用函数
函数可以不带元素名称进行调用(与其他语言中的函数调用类似),也可以 带元素名称调用(与其他语言中的方法调用类似):
import { Button, VerticalBox } from "std-widgets.slint";
export component Example { // Call without an element name: property <string> my-property: my-function(); // Call with an element name: property <int> my-other-property: my_button.my-other-function();
pure function my-function() -> string { return "result"; }
VerticalBox { Text { // Called with a pre-defined element: text: root.my-function(); }
my_button := Button { text: "Click me"; clicked => { self.text = root.my-other-property; } pure function my-other-function() -> int { return 42; } } }}函数可见性
默认情况下,函数是私有的,不能从其他组件中访问。
但是,可以使用 public 或 protected 关键字修改其可访问性。
- 使用
public标注的根级函数可被任何组件访问。
若要在不同组件中访问此类函数,你始终需要一个目标,实际上 意味着调用方组件必须将被调用的组件声明为其子元素之一。
export component HasFunction { public pure function double(x: int) -> int { return x * 2; }}
export component CallsFunction { property <int> test: my-friend.double(1);
my-friend := HasFunction { }}如果函数是在子元素中声明的,即使标记为 public,也无法从 另一个组件中调用它,因为子元素本身不是 public,并且不存在一个有效的目标来 调用该函数:
export component HasFunction { t := Text { public pure function double(x: int) -> int { return x * 2; } }}
export component CallsFunction { // Compiler error! // property <int> test: my-friend.t.double(1);
my-friend := HasFunction { }}在被导出组件中标记为 public 的函数也可以从后端代码(Rust、C++、JS)中调用。 请参阅特定语言的文档了解要使用的生成代码。
- 使用
protected标注的函数只能被直接继承自它的组件访问。
函数与回调
函数和 回调 之间有许多相似之处:
- 它们都是可调用的逻辑/代码块
- 它们以相同的方式被调用
- 它们都可以带有参数和返回值
- 它们都可以被声明为
pure
但它们之间也存在区别:
- 回调中的代码/逻辑可以在后端代码中设置并由后端语言 (Rust、C++、JS)实现,而函数必须完全在 slint 中定义
- 定义回调的语法不同
- 回调可以在不为其分配代码块的情况下声明
- 回调有一种特殊的语法,可使用双向绑定操作符
<=>声明别名 - 回调的可见性始终类似于
public函数
一般来说,使用回调最重要的原因是为了能够从后端代码中处理它们。如果不需要这种能力,请使用 函数。
回调
组件可以声明回调,用于向外部传达状态的 变化。回调通过像调用函数一样“调用”它们来 被触发。
你可以通过使用 => 箭头语法声明一个处理程序来响应回调的调用。 内置的 TouchArea 元素声明了一个 clicked 回调,当用户触摸该元素所覆盖的矩形区域或用鼠标 点击该区域时,该回调会被触发。在下面的示例中,通过声明一个处理程序并调用我们的 自定义回调(hello),将该回调的调用转发给了另一个自定义回调(hello):
export component Example inherits Rectangle { // declare a callback
callback hello;
area := TouchArea { // sets a handler with `=>`
clicked => { // emit the callback
root.hello() } }}也可以为回调添加参数:
export component Example inherits Rectangle { // declares a callback
callback hello(int, string); hello(aa, bb) => { /* ... */ }}回调也可以返回一个值:
export component Example inherits Rectangle { // declares a callback with a return value
callback hello(int, int) -> int; hello(aa, bb) => { aa + bb }}回调参数也可以带有名称。 参数名称目前没有语义上的作用,但它们能提高代码的可读性。
export component Example inherits Rectangle { // Declare a callback with named argument
callback hello(foo: int, bar: string); // The names can be overridden with
// anything when setting a handler
hello(aa, bb) => { /* ... */ }}别名
可以以与双向绑定类似的方式声明回调别名:
export component Example inherits Rectangle { callback clicked <=> area.clicked; area := TouchArea {}}