Mojo函数

正如在语言基础中提到的,Mojo支持两种类型的函数:def和fn函数。您可以在任何函数中使用这两种声明方式,包括main()函数,但它们具有不同的默认行为,如本页面所述。

我们认为def和fn都有很好的用例,并且不认为其中任何一种比另一种更好。选择使用哪种方式取决于个人口味,以及哪种风格最适合给定的任务。

我们相信Mojo在这方面的灵活性是一种超能力,它允许您以最适合项目的方式编写代码。

在结构体内声明的函数称为“方法”,但它们具有与此处描述的“函数”完全相同的特性。

def函数


def函数提供了与Python的def函数相同的动态性和灵活性。例如,这个函数在Python和Mojo中的工作方式相同:

def greet(name):
    greeting = "hello," + name + "!"
    return greeting
def main():
    print(greet("Mojo"))

执行结果如下图:
在这里插入图片描述
在Mojo中,您还可以选择指定参数类型和返回类型。您还可以使用var声明变量,可以带有或不带有显式类型声明。

def greet(name:String) -> String:
    var greeting = "hello," + name + "!"
    return greeting
def main():
    print(greet("Mojo"))

代码执行如下图:
在这里插入图片描述

这样写的作用是编译器确保name是一个字符串,并且返回类型也是一个字符串。

以下是关于def的所有信息:

  • 参数可以不需要声明类型。
    未声明的参数实际上以object的形式传递,这允许函数接收任何类型(Mojo在运行时推断类型)。
    *返回类型也可以不需要声明,也默认为object。
  • 参数是可变的(通常通过按值传递使用owned参数约定)。
    如果参数是object类型,则以引用的方式接收,遵循对象引用语义。
    如果参数是任何其他声明的类型,则以值的方式接收(使用owned参数约定)。
  • 变量可以不需要使用var进行声明。

object类型

如果您在def函数中不声明参数或返回值的类型,则它将成为一个object,这与标准库中的任何其他类型都不同。

object类型允许动态类型,因为它实际上可以表示Mojo标准库中的任何类型,并且实际类型在运行时推断出来(实际上,在它能表示所有Mojo类型之前还有更多的工作要做)。这对于与Python的兼容性非常有用,并且可以提供动态类型所提供的所有灵活性。然而,这种类型缺乏类型强制执行,当函数接收或返回意外类型时会导致运行时错误。

为了与Python兼容,使用对象引用语义来传递object值。因此,object类型与强制执行值语义的参数约定不兼容。因此,如果在其他强类型值旁边使用object值,则它们的行为可能不一致,因为object是标准库中唯一不符合完全值语义的类型。

fn函数


fn函数提供了严格的类型检查和额外的内存安全性。它基本上强制您在def中编写的可选内容,并确保您不会意外地改变接收到的参数。例如,这是使用fn的相同函数:

def greet(name: String) -> String:
    greeting = "hello," + name + "!"
    return greeting
def main():
    print(greet("Mojo"))
    print(greetA("Mojo A"))
fn greetA(name: String) -> String:
    var greeting = "hello," + name + "!"
    return greeting

运行结果如下图:
在这里插入图片描述
对于函数调用者来说,def函数和fn函数是可以互换的。也就是说,def函数可以做的任何事情fn函数也能做(反之亦然)。区别在于,与def函数相比,fn函数在内部更加严格。
关于fn函数的所有内容如下:

  • 参数必须指定类型(结构体方法中的self参数除外)。
  • 返回值必须指定类型,除非函数不返回值。
    如果不指定返回类型,默认为None(表示没有返回值)。
  • 默认情况下,参数以不可变引用的方式接收(值是只读的,使用borrowed参数约定)。
    这可以防止意外的更改,并允许使用不可复制的类型作为参数。
    如果您想要一个局部副本,可以将值赋给一个局部变量。或者,您可以通过声明inout参数约定来获取对值的可变引用。
  • 必须使用var关键字声明变量。
  • 如果函数引发异常,必须使用raises关键字显式声明异常(def函数不需要声明异常)。

通过强制执行这些类型检查,使用fn函数有助于避免各种运行时错误。与def函数中的动态类型相比,它还改善了性能,因为在运行时不需要处理来确定使用什么数据类型所需的开销 - 类型在编译时固定。

可选参数

可选参数是包括默认值的参数,例如这里的exp参数:

fn pow(base: Int, exp: Int = 2) -> Int:
    return base**exp
fn use_defaults():
    # 使用`exp`的默认值
    var z = pow(3)
    print(z)
def main():
    use_defaults()

运行结果如下图:
在这里插入图片描述
但是,您不能为声明为inout的参数定义默认值。

关键字参数


在调用函数时,您还可以使用关键字参数。关键字参数使用格式argument_name = argument_value来指定。您可以以任何顺序传递关键字参数:

fn pow(base: Int, exp: Int = 2) -> Int:
    return base**exp
fn use_defaults():
    # 使用`exp`的默认值
    var z = pow(3)
    print(z)
def main():
    use_defaults()
    print(pow(5, 4))
    print(pow(base=4, exp=2))

运行结果如下图:
在这里插入图片描述

这样可以更加清晰地表达参数的意图,并且不需要记住参数的顺序。

以上是关于函数的全部内容。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JoePotter

您的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值