V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
justonelastdance
V2EX  ›  问与答

函数传参的类型

  •  
  •   justonelastdance · 266 天前 · 948 次点击
    这是一个创建于 266 天前的主题,其中的信息可能已经有所发展或是发生改变。

    一般分为值传递和引用传递,大部分语言都是这样吧。 有没有特殊的语言,只有值传递的?

    14 条回复    2023-08-20 03:15:55 +08:00
    geelaw
        1
    geelaw  
       266 天前 via iPhone
    Java 和 C 都只能传值。
    geelaw
        2
    geelaw  
       266 天前
    另外,JavaScript 也只有传值。

    对于纯函数式语言来说,传引用和传值没有任何区别。
    justonelastdance
        3
    justonelastdance  
    OP
       266 天前
    @geelaw js 有引用传递吧。传对象和数组就是引用传递
    geelaw
        4
    geelaw  
       266 天前
    @justonelastdance #3 一个方法的一个参数是传引用 (pass by reference) 的含义是:实参可以被赋值,且方法内对形参的赋值会导致对实参赋值。

    let a = {};
    function b(c) { c.d = 1; c = null; }
    b(a);
    console.log(a);

    这里 a 不是 {} 那个对象,而是对象引用,a 的值引用了那个对象。b(a) 这个调用中:

    形参 c 的值是实参 a 的值的副本,故一开始 c 也引用了那个对象,透过 c 的值可以操作那个对象,因此 c.d = 1 这句话会改变那个对象,当然,这没有改变 a ,因为 a 不是那个对象,而 a 还是引用了那个对象。

    形参 c 和实参 a 绑定到了不同的存储位置,对 c 的赋值并不影响 a 的值(也就是不影响 a 的值引用了哪个对象),因此 c 是传值。

    最简单的理解 JavaScript 的方法是这样的:这个世界上有两种值,对象实例、对象引用,除了 import 带来的,其他所有变量名都指示互不相同的存储位置,且每个具名的存储位置都只能存储对象引用。( 123 这种 typeof 会得到 'number' 的东西直接理解为不可变对象就好,不要搞什么 primitive value 之说。)
    justonelastdance
        5
    justonelastdance  
    OP
       266 天前
    @geelaw 这个是引用传递,因为 a 和 c 都指向了同一个引用,c 改变了引用的值,a 的值也跟着变了
    geelaw
        6
    geelaw  
       266 天前 via iPhone
    @justonelastdance #5

    a 的值没有变,在 b 退出之前 c 的值是 null ,但 b 退出之后 a 不是 null 。

    另外“a 和 c 都指向同一个引用”是错误的。a 和 c 代表了不同的存储位置,并且进入 b 的时候 a 和 c 所代表的存储位置具有相同的值,这两个相同的值都是对象引用。
    justonelastdance
        7
    justonelastdance  
    OP
       266 天前
    @geelaw a 的值如果不变的话打印出的应该是{},实际打印出的是{d: 1},因为引用改变了值。后面 c=null 是把 c 指向了另一个引用所以不会造成 a 也是 null
    geelaw
        8
    geelaw  
       266 天前   ❤️ 1
    另外,Python 也只有传值,最早的 FORTRAN 只有传引用。

    @justonelastdance #7 您需要复习 JavaScript 基础知识,a 的值是指向那个对象实例的引用,而不是那个对象实例。在 b 的调用中,通过 c (也是指向那个对象的引用)改变了对象实例,当然可以通过 a 看见。

    你当然理解这里发生了什么,但是你的术语用法和计算机科学中的主流用法不符。我暂时找不到教科书,而且我上面的说明已经很明确了,你也可以参考 https://stackoverflow.com/a/7744623/4598348
    Ericcccccccc
        9
    Ericcccccccc  
       266 天前
    都是值传递, 你以为的引用传递是传递了地址值.
    leonshaw
        10
    leonshaw  
       266 天前 via Android
    大部分都是传值,印象里也就 C++, rust 这种有引用传递。简单的区分方法是看函数里 param = xxxx 和函数外 arg = xxxx 是不是同样的效果。
    lance6716
        11
    lance6716  
       266 天前 via Android
    @justonelastdance 可以理解为,“引用”指的是 a 这个 name 和 c 这个 name 是同一个东西,对 c “本身”的改变会影响到 a 。而不是他们是两个东西但是具有相同的值且值是一个指针,并通过 .d 影响了同一对象
    Rache1
        12
    Rache1  
       266 天前
    在看到楼上的回复之前,我都以为在 JavaScript 这种,传一个对象进去,然后再方法内部可以改变对象本身成员的值的情况,对于对象就是按引用传递的,而对于标量这种则是按值传递,函数内部对其的赋值不能改变其外部。我想楼主之前也是这样想的。🫥

    刚刚去查了一下相关资料,没想到 “传递对象,函数内部改变对象成员值” 的情况也叫按值传递。而按引用传递的就是说在函数内可以直接改变源数据。

    受教 💕
    agagega
        13
    agagega  
       266 天前 via iPhone   ❤️ 1
    C/C++传参的模型看起来难,但是最灵活和最能帮助理解的
    netabare
        14
    netabare  
       266 天前 via Android   ❤️ 1
    call by name/call by value 算不算特殊的传参方式?(虽然其实应该是运算策略来着。。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2167 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 00:27 · PVG 08:27 · LAX 17:27 · JFK 20:27
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.