有关函数以 ! 结尾的问题

  1. 以 ! 结尾的函数会改变参数的内容,但是可以定义不以 ! 结尾的函数也能够更改参数的内容,以 ! 结尾是否是一种约定而不是一种语法规定?例子如下:
julia> function f(x)
       push!(x,1)
       end
f (generic function with 1 method)

julia> a=[]
0-element Array{Any,1}

julia> f(a)
1-element Array{Any,1}:
 1

julia> a
1-element Array{Any,1}:
 1
  1. 如果以 ! 结尾只是一种约定,为什么标准库里的函数write更改了参数IOBuffer的内容却不定义为write! ?
julia> io = IOBuffer()
IOBuffer(data=UInt8[...], readable=true, writable=true, seekable=true, append=false, size=0, maxsize=Inf, ptr=1, mark=-1)

julia> write(io, "abcd")
4

julia> String(take!(io))
"abcd"

以!结尾的函数,这种写法是一种约定,表示会带来副作用
下面的我就不知道了:yum:

函数带!应该是警告该函数会改变引用参数所指向的原始数据,而不是拷贝,这只是一个约定,不是语法

后缀 ! 是一种约定。

write 不加可能是出于习惯吧,输出到 io 的 print 系的函数也是都没有加。

好吧,可能确实是这样。我还想既然是约定,为什么官方自己都不遵守。

目前我知道的语言里,严格遵守这个规定的只有Rust了,他们的println!要加个叹号,老的lisp里不用这样做,所以这不是官方的问题,是个习惯问题

更准确地说,! 约定是表示这个函数是 in-place 方法,只是恰好in-place 方法需要从外部导入一个数据并修改它。更多地是为了区分 in-place 与 copy 的方法。 print 和 write 这些并不存在所谓copy的方法也就没有必要强制遵守这个约定。

5 个赞

Rust! 因为那代表一个宏,是语法规定。Julia 宏则强制要求 @Julia 这般强大的宏如果不带 @ 的话会可能重蹈 lisp 的覆辙,搞出一堆方言引发社区分裂。

我好想弄错了 :stuck_out_tongue:

Julia的类型系统本身不能区分mutation操作,所以!只是约定,另外就是作为一个有GC的语言在内存的问题上相对来说更省事一些。而实际上有很多不带!的函数也会改变全局变量,例如rand等等。

rust语言在设计的时候为了严格保证内存安全的零开销抽象,rust的编译器可以做到正确区分mutation操作,所以rust里!可以作为一个语法。

1 个赞