使用 v0.5.0

⚠️一些例子是“最小和简单的”,没有进行安全检查。

这是为了更好地说明概念而不是混乱的头脑,确保在您的实现中遵循良好的实践和安全编码。
让我们学习如何参数化!

教程开始
参数是编译时值。

该示例还涵盖了“结构参数推导”。

它非常有用,尝试练习玩它以记住和理解它。

注意演绎是如何“向上”向上移动的,并填补空白。

感觉参数类型定义了结构的参数,而不是相反。

提高生产率,减少屏幕空间使用,减少重复编码:

@value
struct Point3D[XT:AnyType,YT:AnyType,ZT:AnyType]:
    var x:XT
    var y:YT
    var z:ZT

    fn __init__(inout self, x:XT ,y:YT,z:ZT):
        self.x = x
        self.y = y
        self.z = z

# 4️⃣. use parameters of an argument inside the function signature:
fn to_list_literal(arg:Point3D)-> ListLiteral[arg.XT,arg.YT,arg.ZT]:
    return ListLiteral(arg.x,arg.y,arg.z)

fn main():

    #1️⃣ Explicit struct parameters:
    var my_point_d = Point3D[Int64,Int64,Int64](1,2,3)
    var my_point_e = Point3D[Int64,Float64,Int64](1,2.5,3)
    
    #2️⃣ Struct parameters deduction 
        #XT, YT, ZT deduced from argument passed:

    var my_point_a = Point3D(1, 2, 3)         #Int64, Int64, Int64

    var my_point_b = Point3D(1.0, 2.0, 3.0)   #Float64, Float64, Float64
    
    var my_point_c = Point3D(1, 2.5, 3)       #Int64, Float64, Int64

    #3️⃣ Re-use the parameters of an instance of Point3D
    var some:my_point_c.YT = 1.0 #my_point_c.YT is a type (Float64)

    print(to_list_literal(my_point_a)) # [1, 2, 3]
    print(to_list_literal(my_point_c)) # [1, 2.5, 3]

详见更新日志:v0.5.0-2023-11-2
现在可以在函数的签名中引用函数参数输入参数
Mojo 现在支持结构参数推导

功能自动参数化

我们不接受 arg 的参数,但 DynamicVector 是参数化的。take_dynamic_vector()
长格式版本可能如下所示:

fn take_dynamic_vector[T:AnyType](arg:DynamicVector[T]) -> T:

Mojo 将为我们创建论文以提高工作效率。

为了理解语言,了解这一点很重要。

fn take_dynamic_vector(arg:DynamicVector) -> arg.type:
    let tmp: arg.type = arg[0] #first element of vector
    return tmp

fn main(): 
    var tmp_a = DynamicVector[Int64]()
    var tmp_b = DynamicVector[Float64]()
    var tmp_c = DynamicVector[Bool]()

    tmp_a.push_back(1)
    tmp_b.push_back(1.5)
    tmp_c.push_back(True)

    let a:Int64 = take_dynamic_vector(tmp_a)
    let b = take_dynamic_vector(tmp_b)

    print(a,b)

    #parameters are known at compile time
    #type is a parameter of DynamicVector

    let d:tmp_c.type = False #tmp_c.type == Bool
    let e = take_dynamic_vector(tmp_c)
    print(d==e)

需要时“拉取”参数:
请注意,我们指的是函数签名本身内部的 arg 参数。

fn simd_to_dtype_pointer(arg:SIMD)->DTypePointer[arg.type]:
    var tmp = DTypePointer[arg.type].alloc(arg.size)
    # just to demonstrate unroll, 
    # simd_store is probably way faster:
    @unroll
    for i in range(arg.size):
        tmp.store(i,arg[i])
    return tmp

fn simd_to_static_tuple(arg:SIMD)->StaticTuple[arg.size,SIMD[arg.type,1]]:
    var tmp = StaticTuple[arg.size,SIMD[arg.type,1]]()
    
    #Can be unrolled, because arg.size is known at compile time.
    #Parameters of simd: SIMD[TYPE,SIZE]
    
    @unroll
    for i in range(arg.size):
        tmp[i]=arg[i]
    return tmp

编译器时间常量值(例如别名或参数)是展开循环所必需的。

捕获函数中的动态值并将其作为参数传递
目前 (v0.5) 是不安全的,直到通过引用对捕获值的生存期进行建模。

参见文档:参数装饰器

为了熟悉它,这里是一个介绍:

fn take_parameter[f: fn() capturing -> Int]():
    let val = f()
    print(val)

fn main():

    #will be captured as a reference
    var val = 0
    
    @parameter
    fn closure()->Int:
        return val #captured here
    
    for i in range(5):
        val = i
        take_parameter[closure]()

    _ = val #extend lifetime manually
    #if not extended, would be cleaned at last use.

编译时 if 语句
它是在编译时运行的 if 语句。

这样做的好处是,最终程序中只包含实时分支。

alias use_simd:Bool = SIMD[DType.uint8].size > 1

fn main():
    @parameter
    if use_simd == True:
        print("This build uses simd")
    else:
        print("This build do not uses simd")

每次都会执行在运行时运行的传统 if 语句。

在编译过程中,该命令仅执行一次。

如果满足条件,if 语句块中的内容将包含在程序中。

它引入了一种条件编译的形式。

请注意,任何“编译时就绪”函数都可以在 if 语句中使用。

alias
对于编译时常量,

它们可以作为参数传递,因为它们在编译时是已知的。

fn main():
    alias size = 4
    alias DT = DType.uint8
    var value = SIMD[DT,size](0)
    print(value.size==size)

    #create an alias to the print_no_newline function
    alias say = print_no_newline

    say("hello world")

它们也可以“像 C 中的定义一样”使用

alias TYPE_OF_INT = Int64

fn get_vector()->DynamicVector[TYPE_OF_INT]:
    return DynamicVector[TYPE_OF_INT]()

fn my_add(a:TYPE_OF_INT,b:TYPE_OF_INT)->TYPE_OF_INT:
    return a+b

因为别名是“编译时”,所以它可以存储编译时计算的结果:

fn squared(a:Int) -> Int:
    return a*a

fn main():
    alias pre_calculated_during_compilation = squared(3)
    var calculated_during_runtime = squared(3)
    print(pre_calculated_during_compilation) #9

    alias squared_again_during_compilation = squared(pre_calculated_during_compilation)
    print(squared_again_during_compilation) #81

在编译时,可以分配堆内存并将其具体化以供运行时使用。

fn get_squared[stop_at:Int=10]() -> DynamicVector[Int]:
    var tmp = DynamicVector[Int]()
    for i in range(stop_at):
        tmp.push_back(i*i)
    return tmp

fn main():
    alias the_compile_time_vector = get_vector[stop_at=100]()
    var materialized_for_runtime_use = the_compile_time_vector

参数默认值和关键字
参数可以具有默认值,并由关键字引用。

具有默认值的那些需要在那些没有默认值(顺序)之后定义。

example[no_default:Int, got_default:Int=1]

fn get_vector[VT:AnyType = Int64]()->DynamicVector[VT]:
    return DynamicVector[VT]()

fn main():
    var vec = get_vector()
    vec.push_back(1)

    var vec2 = get_vector[VT=Int32]()
    vec2.push_back(1)

重载:同名,不同类型。
可以在参数和函数/方法上进行重载。

fn take_arg[arg:Float64]():
    print("float64", arg)

fn take_arg[arg:Int64]():
    print("Int64", arg)

fn main():
    alias a:Float64 = 1.0
    alias b:Int64 = 1
    take_arg[a]()
    take_arg[b]()