【Go语言圣经2.5】

目标

了解类型定义不仅告诉编译器如何在内存中存储和处理数据,还对程序设计产生深远影响:

  • 内存结构:类型决定了变量的底层存储(比如占用多少字节、内存布局等)。
  • 操作符与方法集:类型决定了哪些内置运算符适用于它,以及能否为该类型定义方法,从而扩展它的行为。
  • 语义区分:通过定义新类型,即使它们的底层类型相同,也能明确区分不同概念,避免混用(例如温度单位、索引、文件描述符等)。
  • 可读性与安全性:使用命名类型可以让代码语义更明确,从而降低出错的风险。

概念

  1. 每个变量或表达式都有一个类型,类型描述了值的属性,如数据占用的内存大小、内部结构、支持哪些操作以及关联的方法集等。
  2. 一个 int 类型的变量可能用于表示索引、时间戳或月份;一个 float64 类型的变量可能表示速度或温度。尽管底层都是数字,但语义上却截然不同。
  3. 内存与数据表示:每个数据类型在内存中的表示方式(如整数占用 32 位或 64 位)由其底层类型决定。命名类型会沿用相同的存储方式,但在类型系统中赋予它新的含义。
  4. 方法与接收者
    • **方法的定义:**在 Go 中,可以为任意命名类型定义方法,使得该类型的值具有特定行为(如格式化输出)。
    • 调用示例:fmt.Printf 等函数会自动调用类型的 String 方法,从而定制输出格式。
    • 静态分派:fmt.Printf 等函数会自动调用类型的 String 方法,从而定制输出格式。

要点

类型声明语句

type 新类型名称 底层类型

这条语句创建一个新的类型名称,其底层结构与现有类型相同,但在类型系统中被认为是不同的。例如:

type Celsius float64    // 摄氏温度类型
type Fahrenheit float64 // 华氏温度类型

即使 Celsius 和 Fahrenheit 都基于 float64,它们是两个不同的类型,防止你无意中混用不同温度单位的数据。

  • 命名规则与导出
    • 如果新类型名称的首字符大写,则表示该类型对包外可见(导出)。
    • Go 语言中关于 Unicode 字母的规则也使得中文命名默认不能导出(Go 1 的规则),但在将来的 Go 2 中可能会调整。
  • 用途
    • 语义区分:通过定义不同的命名类型(即使底层相同)可以让程序更安全,不会将代表不同概念的值误用在一起。
    • 简化代码:对于复杂或冗长的类型,用一个简单的名称可以使代码更清晰易读。

类型转换操作

  1. 操作形式

    类型转换写作 T(x),它不会改变 x 的实际值,只是将它“贴上”新的类型标签

    var f Fahrenheit = CToF(BoilingC)
    fmt.Println(Celsius(f)) // 将 f 转换为 Celsius 类型
    
    • 限制:只有当两个类型的底层类型完全相同时,或者都是指向相同底层结构的指针时,才能进行转换。
  2. 作用

    通过类型转换,可以将同样底层数据但语义不同的值显式转换,使得运算和比较变得类型安全。例如

    var c Celsius
    var f Fahrenheit
    // c == f // 编译错误:类型不匹配
    fmt.Println(c == Celsius(f)) // 显式转换后可以比较
    

类型与方法

  1. 方法集

    命名类型不仅是一个新的数据类型,还可以为该类型定义方法,这使得它拥有特定的行为。

    func (c Celsius) String() string {return fmt.Sprintf("%g°C", c)
    }
    

    这段代码为 Celsius 类型定义了一个 String 方法,在调用 fmt.Printf 时会自动调用该方法来格式化输出。(因为 fmt 包会自动调用 String 方法)(具体一点说:当一个类型实现了 String() string 方法后,它就满足了 fmt 包定义的 Stringer 接口。fmt 包在格式化输出时,会检查传入的值是否实现了该接口,如果实现了,就自动调用 String() 方法来获取该值的字符串表示。)

    c := FToC(212.0)
    fmt.Println(c.String()) // 输出 "100°C"
    fmt.Printf("%v\n", c)   // 也输出 "100°C",因为 fmt 包会自动调用 String 方法

    为类型定义方法不仅增加了代码的可读性,也让类型更具语义。

如何定义 Celsius 与 Fahrenheit 两个命名类型及它们之间的转换和方法

// Package tempconv performs Celsius and Fahrenheit temperature computations.
package tempconvimport "fmt"type Celsius float64    // 定义摄氏温度类型
type Fahrenheit float64 // 定义华氏温度类型// 常量声明
const (AbsoluteZeroC Celsius = -273.15 // 绝对零度(摄氏)FreezingC     Celsius = 0       // 冰点(摄氏)BoilingC      Celsius = 100     // 沸点(摄氏)
)// CToF 将摄氏温度转换为华氏温度
func CToF(c Celsius) Fahrenheit { return Fahrenheit(c*9/5 + 32) 
}// FToC 将华氏温度转换为摄氏温度
func FToC(f Fahrenheit) Celsius { return Celsius((f - 32) * 5 / 9) 
}// Celsius 的 String 方法,使其输出更友好
func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) 
}
  • Celsius 类型的 String 方法为其提供了定制格式,当使用 fmt 包打印时,会自动调用此方法。

类型比较与运算

  • 支持内置运算符

    因为 Celsius 和 Fahrenheit 的底层类型都是 float64,所以它们可以使用底层类型的算术和比较运算符。例如:

    
    fmt.Printf("%g\n", BoilingC-FreezingC) // 输出 "100"
    boilingF := CToF(BoilingC)
    fmt.Printf("%g\n", boilingF-CToF(FreezingC)) // 输出 "180"
    

    注意,直接将 Fahrenheit 与 Celsius 进行运算会导致编译错误,因为它们是不同的命名类型。

  • 比较运算

    只有相同类型之间才能进行直接比较:

    var c Celsius
    var f Fahrenheit
    fmt.Println(c == 0)          // "true",0 会被视为 Celsius 类型的零值
    fmt.Println(f >= 0)          // "true",同理,0 对于 Fahrenheit 也是零值
    // fmt.Println(c == f)       // 编译错误:类型不匹配
    fmt.Println(c == Celsius(f)) // 正确:通过类型转换后比较
    

总结

  1. 类型定义描述了变量的内存表示、支持的运算符和方法集,同时区分不同的语义。
  2. 将不同的概念定义为不同的命名类型,即使它们底层相同,也能在编译期防止错误的混用。(例如,不小心将温度与文件描述符混用可能引发错误,通过定义不同类型就可以避免这种情况。)
  3. 类型转换 T(x) 只改变 x 的类型标签而不改变底层数据。转换要求两个类型有相同的底层类型或兼容的结构。
  4. 方法与类型行为:为命名类型定义方法(如 String 方法),使得在打印和其它操作时可以自动调用,增强了类型的表现力。
  5. 新类型继承了底层类型的算术与比较操作,但必须保证操作数类型一致。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/72523.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IDEA 一键完成:打包 + 推送 + 部署docker镜像

1、本方案要解决场景? 想直接通过本地 IDEA 将最新的代码部署到远程服务器上。 2、本方案适用于什么样的项目? 项目是一个 Spring Boot 的 Java 项目。项目用 maven 进行管理。项目的运行基于 docker 容器(即项目将被打成 docker image&am…

SpringBoot 第一课(Ⅲ) 配置类注解

目录 一、PropertySource 二、ImportResource ①SpringConfig (Spring框架全注解) ②ImportResource注解实现 三、Bean 四、多配置文件 多Profile文件的使用 文件命名约定: 激活Profile: YAML文件支持多文档块&#xff…

深度解析React Native底层核心架构

React Native 工作原理深度解析 一、核心架构:三层异构协作体系 React Native 的跨平台能力源于其独特的 JS层-Shadow层-Native层 架构设计,三者在不同线程中协同工作: JS层 运行于JavaScriptCore(iOS)或Hermes&…

对话智能体的正确打开方式:解析主流AI聊天工具的核心能力与使用方式

一、人机对话的黄金法则 在与人工智能对话系统交互时,掌握以下七项核心原则可显著提升沟通效率:文末有教程分享地址 意图精准表达术 采用"背景需求限定条件"的结构化表达 示例优化:"请用Python编写一个网络爬虫&#xff08…

Xinference大模型配置介绍并通过git-lfs、hf-mirror安装

文章目录 一、Xinference开机服务systemd二、语言(LLM)模型2.1 配置介绍2.2 DeepSeek-R1-Distill-Qwen-32B(大杯)工具下载git-lfs(可以绕过Hugging Face) 2.3 DeepSeek-R1-Distill-Qwen-32B-Q4_K_M-GGUF&am…

MyBatis操纵数据库-XML实现(补充)

目录 一.多表查询二.MyBatis参数赋值(#{ }和${ })2.1 #{ }和${ }的使用2.2 #{ }和${ }的区别2.3 SQL注入2.3 ${ }的应用场景2.3.1 排序功能2.3.2 like查询 一.多表查询 多表查询的操作和单表查询基本相同,只需改变一下SQL语句,同时也要在实体类中创建出…

快速导出接口设计表——基于DOMParser的Swagger接口详情半自动化提取方法

作者声明:不想看作者声明的(需要生成接口设计表的)直接前往https://capujin.github.io/A2T/。 注:Github Pages生成的页面可能会出现访问不稳定,暂时没将源码上传至Github,如有需要,可联系我私…

TS常见内置映射类型的实现及应用场景

以下是 TypeScript 在前端项目中 常用的映射类型&#xff08;Mapped Types&#xff09;&#xff0c;结合具体场景和代码示例&#xff0c;帮助开发者高效处理复杂类型&#xff1a; 一、基础映射类型 1. Partial<T> 作用&#xff1a;将对象类型 T 的所有属性变为可选。 实…

介绍如何使用YOLOv8模型进行基于深度学习的吸烟行为检测

下面为你详细介绍如何使用YOLOv8模型进行基于深度学习的吸烟行为检测&#xff0c;包含环境配置、数据准备、模型训练以及推理等步骤。 1. 环境配置 首先&#xff0c;你需要安装必要的库&#xff0c;主要是ultralytics库&#xff0c;它包含了YOLOv8模型。你可以使用以下命令进…

AI-医学影像分割方法与流程

AI医学影像分割方法与流程–基于低场磁共振影像的病灶识别 – 作者:coder_fang AI框架&#xff1a;PaddleSeg 数据准备&#xff0c;使用MedicalLabelMe进行dcm文件标注&#xff0c;产生同名.json文件。 编写程序生成训练集图片&#xff0c;包括掩码图。 代码如下: def doC…

【Python】09、字典

文章目录 1. 字典简介2. 字典的使用2.1 字典创建2.2 字典值获取2.3 字典值修改2.4 字典的删除 3. 字典的遍历 1. 字典简介 字典(dict)属于一种新的数据结构&#xff0c;称为映射(mapping)。 字典的作用和列表类似&#xff0c;但是查询性能比列表好&#xff1b;在字典中每个元…

【贪心算法4】

力扣452.用最少数量的剪引爆气球 链接: link 思路 这道题的第一想法就是如果气球重叠得越多那么用箭越少&#xff0c;所以先将气球按照开始坐标从小到大排序&#xff0c;遇到有重叠的气球&#xff0c;在重叠区域右边界最小值之前的区域一定需要一支箭&#xff0c;这道题有两…

SGMEA: Structure-Guided Multimodal Entity Alignment

3 Method 3.1 Problem Definition 3.2 Framework Description 总体框架如图2所示&#xff0c;由三个主要部分组成&#xff1a;初始嵌入采集模块、结构引导模块和模态融合模块。 3.3 Initial Embedding Acquisition 3.3.1 Structural Embedding 3.3.2 Relation, Attribute, …

KY-038 声音传感器如何工作以及如何将其与 ESP32 连接

想为您的项目赋予声音感!然后跟着做,因为在这个项目中,我们将连接一个声音传感器,用它构建一些有趣的项目。我们使用的 KY-038 声音传感器使用电容式麦克风来检测声波,这为我们提供了稳定性和可靠性的完美平衡。因此,在本文中,我们决定将 KY-038 传感器与 ESP32 连接,并…

《基于超高频RFID的图书馆管理系统的设计与实现》开题报告

一、研究背景与意义 1.研究背景 随着信息化时代的到来&#xff0c;运用计算机科学技术实现图书馆的管理工作已成为优势。更加科学地管理图书馆会大大提高工作效率。我国的图书管理体系发展经历了三个阶段&#xff1a;传统图书管理模式、现代图书管理模式以及基于无线射频识别&…

[local-file-system]基于服务器磁盘的本地文件存储方案

[local-file-system]基于服务器磁盘的本地文件存储方案 仅提供后端方案 github 环境 JDK11linux/windows/mac 应用场景 适用于ToB业务&#xff0c;中小企业的单体服务&#xff0c;仅使用磁盘存储文件的解决方案 仅使用服务器磁盘存储 与业务实体相结合的文件存储方案&…

P5708 【深基2.习2】三角形面积(洛谷—python)

题目描述 一个三角形的三边长分别是 a、b、c&#xff0c;那么它的面积为 p(p−a)(p−b)(p−c)​&#xff0c;其中 p21​(abc)。输入这三个数字&#xff0c;计算三角形的面积&#xff0c;四舍五入精确到 1 位小数。 输入格式 第一行输入三个实数 a,b,c&#xff0c;以空格隔开…

智慧加油站小程序数据库设计文档

智慧加油站系统 - 数据库与API设计文档 1. 数据库设计 1.1 ER模型 系统的核心实体关系如下&#xff1a; 用户(User) ---< 订单(Order) ---< 加油记录(RefuelRecord)| | || | vv v …

C++博客分享

本周的一些 C视频分享, 或许后续会做一些内容总结. 博客 Polymorphic, Defaulted EqualityConstexpr factors_ofC26: Removing language featuresBypassing the branch predictor Meeting C 2024 Clean CMake for C (library) developers - Kerstin KellerAn Introduction …

【蓝桥杯每日一题】3.16

&#x1f3dd;️专栏&#xff1a; 【蓝桥杯备篇】 &#x1f305;主页&#xff1a; f狐o狸x 目录 3.9 高精度算法 一、高精度加法 题目链接&#xff1a; 题目描述&#xff1a; 解题思路&#xff1a; 解题代码&#xff1a; 二、高精度减法 题目链接&#xff1a; 题目描述&…