Mojo被设计为Python的超集,如果了解Python,那么Mojo代码的入门也不难。 Mojo旨在解决其他任何语言都无法解决的各种人工智能开发挑战,因为Mojo是第一种从头开始使用MLIR(一种理想的用于异构硬件的编译器基础设施,从CPU和GPU到各种人工智能ASIC)构建的编程语言。
(1)执行:curl -s https://get.modular.com | sh -
(2)执行:modular auth
,会提示 To complete auth, open this web page:
,然后打开对应的链接地址,然后登录到页面,过一会就可以授权到当前你使用的设备
(3)安装 Mojo SDK,执行:modular install mojo
(4)最后一步,设置当前环境变量:
MOJO_PATH=$(modular config mojo.path) \
&& BASHRC=$( [ -f "$HOME/.bash_profile" ] && echo "$HOME/.bash_profile" || echo "$HOME/.bashrc" ) \
&& echo 'export MODULAR_HOME="'$HOME'/.modular"' >> "$BASHRC" \
&& echo 'export PATH="'$MOJO_PATH'/bin:$PATH"' >> "$BASHRC" \
&& source "$BASHRC"
(5)查看mojo的版本:mojo --version
,退出命令行:ctrl + d
(6)更新mojo:modular update mojo
(7)在线尝试mojo,可以打开:https://docs.modular.com/mojo/playground
(1)进入命令行:mojo
MacBook-Pro ~ % mojo
Welcome to Mojo! 🔥
Expressions are delimited by a blank line.
Type `:quit` to exit the REPL and `:mojo help` for further assistance.
1>
(2)输入:print("Hello, world!")
1> print("Hello, world!")
2.
Hello, world!
(3)创建hello.mojo
文件,然后执行:
fn main():
print("Hello, world!")
mojo hello.mojo
输出:Hello, world!
(4)编译:
mojo build hello.mojo
./hello
输出:Hello, world!
(1)函数定义:
def
允许非类型声明和动态行为(Python 风格)def
定义的函数则不需要声明类型fn
声明强制执行类型检查和内存安全行为(Rust 风格)fn
定义的函数中必须声明参数和返回的类型,除非函数不返回值fn
定义的函数,如果函数引发异常,必须使用 raises
关键字显式声明异常object
类型main
函数fn pow(base: Int, exp: Int = 2) -> Int:
(2)函数参数传递:按值传递还是按引用传递
def
定义的函数通过值传递参数fn
定义的函数通过不可变引用传递参数(3)变量声明:可以通过 var
声明变量
def
定义的函数声明变量可以忽略 var
fn
定义的函数声明的变量类型是可选的var name1: String = "aaa"
或者 var name2 = String("aaa")
fn do_math(x : Int):
var y : Int = 1
y = x + y
y = y * y
print(y)
(4)结构体:类似的 python
的 class
__init__()
方法,其中 __init__()
方法第一个参数是 inout self
self
,用于访问当前结构体实例@staticmethod
,访问方式用实例或者struct名都可以运行__init__
,__del__
等,也可以@value合成__moveinit__
,__copyinit__
等结构体方法struct MyPair:
var first: Int
var second: Int
# var third: Int # 如果不在__init__赋值,就会编译报错
fn __init__(inout self, first: Int, second: Int):
self.first = first
self.second = second
fn dump(self):
print(self.first, self.second)
@staticmethod
fn log_info(message: String):
print("Info: ", message)
fn main():
var mine = MyPair(2, 4)
mine.dump()
(5)trait
:类似 golang
的 interface
和 rust
的 trait
,通过让定义一组共享的行为,让类型可以实现这些行为来解决此问题
trait
定义的结构体,必须实现每个 trait
的函数trait
不具备默认的函数方法trait
支持继承,可以让 trait
继承多个其他的 trait
Traits
例如:AnyType,Boolable,Movable,Stringable,Copyable ...trait Quackable:
fn quack(self): ...
@value
struct Duck(Quackable):
fn quack(self):
print("Quack")
@value
struct StealthCow(Quackable):
fn quack(self):
print("Moo!")
fn make_it_quack[T: Quackable](maybe_a_duck: T):
maybe_a_duck.quack()
struct MyList(Sized):
var size: Int
# ...
fn __init__(inout self):
self.size = 0
fn __len__(self) -> Int:
return self.size
print(len(MyList()))
(5)元编程
fn sum_params[*values: Int]() -> Int:
struct GenericArray[T: AnyRegType]:
var data: Pointer[T]
var size: Int
fn __init__(inout self, *elements: T):
self.size = len(elements)
self.data = Pointer[T].alloc(self.size)
for i in range(self.size):
self.data[i] = elements[i]
fn __del__(owned self):
self.data.free()
fn __getitem__(self, i: Int) raises -> T:
if (i < self.size):
return self.data[i]
else:
raise Error("Out of bounds")
(6)值的生命周期 在Mojo中,一个值的生命周期从变量初始化开始,直到该值最后被使用时Mojo销毁它,包括构造函数,复制构造函数,移动构造函数等。
__init__
成员函数执行就开始执行初始化,可以重载构造函数,比如创建多个 fn __init__(inout self, ...)
__copy__
成员函数执行复制新的实例,类似C++中的成员函数__move__
成员函数执行移动构造函数来实现结构体的移动,移动构造函数也返回一个新的实例,并且我们必须将其分配给一个新的变量struct MyPet:
var name: String
var age: Int
fn __init__(inout self, name: String, age: Int):
self.name = name
self.age = age
fn __copyinit__(inout self, existing: Self):
print("this is __copyinit__")
self.name = existing.name
self.age = existing.age
fn dump(inout self):
print(self.name, self.age)
Mojo提供了一个包装系统,允许将代码库组织和编译成可导入的文件。
(1)Mojo模块
import mymodule as my
(2)Mojo包 Mojo包是包含__init__.mojo文件的目录中的Mojo模块集合,通过将模块组织在一个目录中,可以一起或单独导入所有模块,目录结构可以如下:
main.mojo
mypackage/
__init__.mojo
mymodule.mojo
然后可以在main.mojo
这样导入:from mypackage.mymodule import {模块}
。
(1)导入Python模块
比如导入使用numpy,可以先导入python,如下:
from python import Python
fn use_array() raises:
# 这相当于Python中的`import numpy as np`
var np = Python.import_module("numpy")
# 现在可以像在Python中编写一样使用numpy
var array = np.array([1, 2, 3])
print(array)
前提条件是:
(2)使用Python类型
var py_list: PythonObject = [1, 2, 3, 4]
Python.evaluate()
创建python的类型,方便在Mojo中使用fn python_types():
try:
from python import Python
from python.object import PythonObject
var value1: PythonObject = 3.7
var value2 = Python.evaluate("10/3")
var float_type = Python.evaluate("float")
print(Python.type(value1)) # <class 'float'>
print(Python.is_type(Python.type(value1), Python.type(value2))) # True
print(Python.is_type(Python.type(value1), float_type)) # True
print(Python.is_type(Python.type(value1), Python.none())) # False
except:
pass
为了方便大家验证和测试,我提供了一些测试代码,可以直接在 playground
上运行:
var testName: String = "aaa"
def greet2(name):
return "Hello, " + name + "!"
fn do_math(x : Int):
var y = 1
y = x + y
y = y * y
print(y)
struct MyPair:
var first: Int
var second: Int
# var third: Int
fn __init__(inout self, first: Int, second: Int):
self.first = first
self.second = second
fn dump(self):
print(self.first, self.second)
fn python_types():
try:
from python import Python
from python.object import PythonObject
var value1: PythonObject = 3.7
var value2 = Python.evaluate("10/3")
var float_type = Python.evaluate("float")
print(Python.type(value1)) # <class 'float'>
print(Python.is_type(Python.type(value1), Python.type(value2))) # True
print(Python.is_type(Python.type(value1), float_type)) # True
print(Python.is_type(Python.type(value1), Python.none())) # False
except:
pass
trait Quackable:
fn quack(self): ...
@value
struct Duck(Quackable):
fn quack(self):
print("Quack")
@value
struct StealthCow(Quackable):
fn quack(self):
print("Moo!")
fn make_it_quack[T: Quackable](maybe_a_duck: T):
maybe_a_duck.quack()
struct MyList(Sized):
var size: Int
fn __init__(inout self):
self.size = 0
fn __len__(self) -> Int:
return self.size
struct GenericArray[T: AnyRegType]:
var data: Pointer[T]
var size: Int
fn __init__(inout self, *elements: T):
self.size = len(elements)
self.data = Pointer[T].alloc(self.size)
for i in range(self.size):
self.data[i] = elements[i]
fn __del__(owned self):
self.data.free()
fn __getitem__(self, i: Int) raises -> T:
if (i < self.size):
return self.data[i]
else:
raise Error("Out of bounds")
struct MyPet:
var name: String
var age: Int
fn __init__(inout self, name: String, age: Int):
self.name = name
self.age = age
fn __copyinit__(inout self, existing: Self):
print("this is __copyinit__")
self.name = existing.name
self.age = existing.age
fn dump(inout self):
print(self.name, self.age)
fn main():
do_math(100)
var mine = MyPair(2, 4)
mine.dump()
print("Hello, world!")
python_types()
make_it_quack(Duck())
make_it_quack(StealthCow())
print(len(MyList()))
print("Parameterization: compile-time metaprogramming")
try:
var array = GenericArray[Int](1, 2, 3, 4)
for i in range(array.size):
print(array[i], sep=" ", end=" ")
except:
pass
var mine1 = MyPet("Loki", 4)
var yours = mine1
yours.dump()
(1) https://docs.modular.com/mojo/manual/basics (2) https://mojocn.org/mojo/manual (3) https://docs.modular.com/mojo/playground