Swift中的指针类型
Swift编程语言为了能与Objective-C与C语言兼容,而引入了指针类型。尽管官方不建议频繁使用指针类型,但很多时候,使用指针能完成更多、更灵活的任务。比如,我们要实现一个交换两个整数值的函数的时候就不得不动用指针了。就表达上,Swift使用UnsafePointer来表示指向一个常量的指针;使用UnsafeMutablePointer来表示指向一个变量的指针,也是比较直观。不过目前大多Swift开发者对于Swift指针类型的运用不太娴熟,而且官方的编程指南也没怎么提,所以俺这里将写一篇博文来详细给各位介绍一下Swift中的指针类型以及其各种用法~
//
// ViewController.swift
// SwiftTest
//
// Created by Zenny Chen on 16/4/1.
// Copyright © 2016年 GreenGames Studio. All rights reserved.
// import Cocoa /// 对输入一个数组缓存的每个元素进行求和,然后返回求和结果 <br/>
/// 最后,将该数组缓存中的中间一个元素修改为求和的结果值
func myTest(array: UnsafeMutablePointer<Int>, count: Int) -> Int {
var sum = var i = while i < count {
// tmp的值为array第i个元素的值
let tmp = array.advancedBy(i).memory
sum += tmp
i +=
} array.advancedBy(count / ).memory = sum return sum
} /// 将srcArray中后一半的元素拷贝到dstArray中的前一半中去
func myTest2(dstArray: UnsafeMutablePointer<Int>, srcArray: UnsafePointer<Int>, count: Int) {
// 这里通过构造方法将UnsafePointer<Int>转为UnsafeMutablePointer<Int>类型
dstArray.assignBackwardFrom(UnsafeMutablePointer<Int>(srcArray).advancedBy(count / ), count: count / + )
} /// 将srcArray中前一半的元素拷贝到dstArray中的前一半中去
func myTest3(dstArray: UnsafeMutablePointer<Int>, srcArray: UnsafePointer<Int>, count: Int) { // 这里从srcArray的第二个元素开始,拷贝count / 2 + 1个元素
dstArray.assignFrom(UnsafeMutablePointer<Int>(srcArray.advancedBy()), count: count / + )
} /// 用于测试distanceTo方法
func myTest4(array: UnsafeMutablePointer<Int>, count: Int) { // 这里,distanceTo就相当于distanceTo的参数所在的元素位置与array所在的位置的差
// 相当于(distanceTo参数的地址 - array的地址) / sizeof(Int)
let distance = array.distanceTo(array.advancedBy(count / ))
print("distance = \(distance)")
} class ViewController: NSViewController { override func viewDidLoad() {
super.viewDidLoad() // Do any additional setup after loading the view.
// 声明一个变量a,并用10对它初始化
var a = let ptr: UnsafeMutablePointer<Int> = UnsafeMutablePointer<Int>(bitPattern: 0x1000) let bptr = UnsafeMutableBufferPointer(start:&a, count:)
bptr[] += let cptr = UnsafeMutablePointer<Int>(bptr.baseAddress)
cptr.memory += print("a = \(a)") var x =
let p = getMutablePointerType(&x)
p.memory +=
print("x = \(x)") var array = [, , , , ] let value = myTest(&array, count: array.count) print("value = \(value), and array is: \(array)") let doubleArray: [[Int]] = [ [, , ], [, ], [, , , , ] ]
for arr in doubleArray {
print("array length: \(arr.count)")
} array = [Int](count: , repeatedValue: )
myTest2(&array, srcArray: [, , , , ], count: array.count)
print("array is: \(array)") array = [Int](count: , repeatedValue: )
myTest3(&array, srcArray: [, , , , ], count: array.count)
print("array is: \(array)") myTest4(&array, count: array.count)
} override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}
}
在上述代码例子中,我们主要描述了UnsafeMutablePointer类型的特性与常用方法的使用描述。一开始,我们定义了一个
getMutablePointerType函数用于方便地获得一个变量的指针。
myTest函数描述了UnsafeMutablePointer的advancedBy方法以及memory方法的使用以及功能。
myTest2函数描述了assignBackwardFrom函数的使用以及功能
myTest3函数描述了assignFrom函数的使用以及功能
myTest4函数描述了distanceTo函数的使用以及功能
这里大家要注意的是,在Swift中由于函数是一个闭包,所以只有“函数对象”这个概念,所以不存在指向函数的指针,只有函数对象引用。如果有外部C语言的API存在指向函数指针类型,则需要用@convention(c)去做转换处理。
我们下面举一个例子,主要描述二维数组如果通过指针进行操作的例子
//
// ViewController.swift
// SwiftTest
//
// Created by Zenny Chen on 16/4/1.
// Copyright © 2016年 GreenGames Studio. All rights reserved.
// import Cocoa /// 此函数用于将一个变量转换为指向该变量的常量指针对象
func getConstPointerType<T> (ptr: UnsafePointer<T>) -> UnsafePointer<T> {
return ptr
} /// 此函数用于将一个变量转换为指向该变量的变量指针对象
func getMutablePointerType<T> (ptr: UnsafeMutablePointer<T>) -> UnsafeMutablePointer<T> {
return ptr
} class ViewController: NSViewController { override func viewDidLoad() {
super.viewDidLoad() // Do any additional setup after loading the view. var array = [[, , ], [, , , ]] // 定义一个指向元素为数组类型的数组对象的指针
let p = getMutablePointerType(&array) // 此时,p.memory的类型为[Int]
// 将p的第1个元素的第2个元素的值加10
p.memory[] += // 将p的第2个元素的第4个元素的值加100
p.advancedBy().memory[] += print("array = \(array)") let funcRef: @convention(c) () -> Int32 = MyCFunc print("value is: \(funcRef())")
} override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}
}
通过上述代码,我们可以注意到,在Swift中,一个二维数组其实就是以数组对象作为元素的数组对象。该数组对象的每个元素是一个数组对象引用。因此在用指针操作的时候,其实就是先对某一个数组对象进行操作,访问其里面的一个元素。
此外,Swift中的UnsafeMutablePointer、UnsafeMutableBufferPointer等指针类型对象对具体对象的引用都属于弱引用,也就是说它们的引用以实际对象来看是完全被别名化的,指针对实际对象的操作跟直接用实际对象的引用对对象操作的效果是完全等价的,所以Apple官方称这些类型为“non-owning pointer”。下面举一个例子:
class MyClass {
deinit {
print("MyClass is destroyed!")
}
} class ViewController: NSViewController { override func viewDidLoad() {
super.viewDidLoad() var myObj: MyClass? = MyClass()
var objptr = UnsafeMutableBufferPointer(start: &myObj, count: )
// 这句话与myObj = nil的效果完全一样,
// 这句话执行完之后就会打印:MyClass is destroyed!
objptr.baseAddress.memory = nil
}
}
以下展示用Swift来玩二级指针,其实与C语言的也类似:
class ViewController: NSViewController { override func viewDidLoad() {
super.viewDidLoad() var a = var size = sizeofValue(a)
print("size = \(size)") size = sizeof(ViewController)
print("size = \(size)") var arr = [, , ]
print("The size is: \(sizeofValue(arr))") var ptr = getMutablePointer(&a)
ptr[] +=
print("The value is: \(a)") let pp = getMutablePointer(&ptr) var b = ptr = getMutablePointer(&b)
pp[][] += print("b = \(b)") pp[] = getMutablePointer(&a)
pp[][] -=
print("a = \(a)")
}
}
看完上述Swift中指针操作的场景之后,本人蛋疼地用C++也封装了一些基本类型,可基本模拟出Swift对指针的操作访问模式。
//
// hello.cpp
// CDemo
//
// Created by Zenny Chen on 16/4/1.
// Copyright © 2016年 GreenGames Studio. All rights reserved.
// #include <iostream>
#include <functional>
using namespace std; #define object auto struct Int
{
private: int mValue; public: Int(void) : mValue(0) { } Int(int i) : mValue(i) { } inline Int& operator = (int value)
{
mValue = value; return *this;
} inline Int& operator = (Int& obj)
{
mValue = obj.mValue;
return *this;
} inline operator int& (void)
{
return mValue;
} inline operator const int (void) const
{
return mValue;
} inline size_t size(void) const
{
return sizeof(mValue);
} inline Int* address(void)
{
return this;
} inline const char* typeName(void) const
{
return "Int";
}
}; template <typename T>
struct ptr
{
private: T *mPtr; public: ptr(void) : mPtr(NULL){ } ptr(T *t) : mPtr(t) { } inline T& memory(void)
{
return *mPtr;
} inline T& memory(int index)
{
return mPtr[index];
} inline const T& memory(void) const
{
return *mPtr;
} inline const T& memory(int index) const
{
return mPtr[index];
} inline ptr<T> advancedBy(int count)
{
return ptr<T>(&mPtr[count]);
} inline ptr<T>& operator = (T* t)
{
mPtr = t;
return *this;
} inline ptr<T>& operator = (ptr<T>& p)
{
mPtr = p;
return *this;
} inline ptr<T>* address(void)
{
return this;
} inline size_t size(void) const
{
return sizeof(mPtr);
} inline uintptr_t value(void) const
{
return (uintptr_t)mPtr;
}
}; template <typename T, size_t S>
struct myArray
{
private: T mArray[S]; public: myArray(void)
{
memset(mArray, 0, sizeof(mArray));
} myArray(T arr[S])
{
memcpy(mArray, arr, sizeof(mArray));
} inline myArray<T, S>& operator = (myArray<T, S>& arr)
{
memcpy(mArray, arr.mArray, sizeof(mArray));
return *this;
} inline myArray<T, S> *address(void)
{
return this;
} inline T& operator [] (size_t index)
{
return mArray[index];
} inline size_t size(void) const
{
return sizeof(mArray);
} inline size_t count(void) const
{
return S;
}
}; template <typename FP>
class func : public function<FP>
{
private: void *mp; public: func(FP *fun) : function<FP>(fun)
{
mp = (void*)fun;
} inline size_t size(void) const
{
return sizeof(void*);
} inline ptr< func<FP> > address(void)
{
return this;
} inline uintptr_t functionAddress(void)
{
return (uintptr_t)mp;
}
}; #pragma mark - 以下为对本语言系统的使用 static void MySwap(ptr<Int> a, ptr<Int> b)
{
int tmp = a.memory();
a.memory() = b.memory();
b.memory() = tmp;
} extern "C" void CPPTest(void)
{
Int a = 100;
printf("size of a = %zu\n", a.size()); // object可表示任一对象,并且其类型根据 = 右操作数进行推导
object b = a;
printf("b type is: %s\n", b.typeName()); // 指向变量的指针
ptr<Int> p = a.address(); p.memory() += 10; printf("a = %d\n", a);
printf("size of p = %zu\n", p.size()); // 指向常量的指针
ptr<const Int> cp = a.address(); // error ==> cp.memory() -= 10; printf("memory = %d\n", cp.memory()); // 指向指针的指针
ptr< ptr<Int> > pp = p.address();
printf("content is: %d\n", pp.memory().memory()); pp.memory() = NULL; // 指针p变为空
printf("p value is: %zu\n", p.value()); myArray<Int, 3> arr = (Int[]){ 1, 2, 3 };
printf("size is: %zu, count is: %zu\n", arr.size(), arr.count()); // 指向一个数组首地址的指针
p = arr[0].address();
printf("element 1 = %d\n", p.advancedBy(1).memory());
printf("element 2 = %d\n", p.memory(2)); // 将指针指向数组第二个元素的地址
p = arr[1].address();
printf("p[1] = %d\n", p.memory(1)); // 指向数组的指针
ptr< myArray<Int, 3> > pArr = arr.address();
printf("element 2 = %d\n", pArr.memory()[2]); // 数组赋值
myArray<Int, 3> arr2; arr2 = arr;
arr2[0]++;
arr2[1]--; pArr = arr2.address();
printf("arr2[0] = %d\n", pArr.memory()[0]);
printf("arr2[1] = %d\n", pArr.memory()[1]); // 通过指针间接将arr的值赋给pArr所指向的数组对象arr2
pArr.memory() = arr;
printf("arr2[0] = %d\n", arr2[0]);
printf("arr2[1] = %d\n", arr2[1]); // 关于cv限定符对复杂类型的修饰
// 相当于:const int* const *qq = &cp;
ptr<const ptr<const Int>> qq = cp.address(); // qq.memory() = NULL; Error!
// qq.memory().memory() = 0; // Error! a = qq.memory().memory(); // OK
printf("a = %d\n", a); qq = NULL; // OK
printf("qq value is: %d\n", qq.value()); Int x = 10, y = -10; // 定义一个函数对象
func<void(ptr<Int>, ptr<Int>)> fun = MySwap;
printf("fun size is: %zu\n", fun.size()); fun(x.address(), y.address());
printf("x = %d, y = %d\n", x, y); ptr< func<void(ptr<Int>, ptr<Int>)> > pFunc = fun.address();
pFunc.memory()(x.address(), y.address());
printf("x = %d, y = %d\n", x, y); printf("fun object address: %.16tX\n", fun.address().value());
printf("MySwap address: %.16tX\n", fun.functionAddress());
}
各位可以实践一下,用的是GNU++14标准~
Swift中的指针类型的更多相关文章
- 关于Swift中的指针的那些事
前言 在Objective-c的世界中,一切对象都是指针.它是一种运行时语言,具体指针的对象类型将会在运行时,由系统分配.这样虽然自由,但是却并不安全. Swift世界就不一样了,Swift的世界很安 ...
- Swift——(六)Swift中的值类型
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/twlkyao/article/details/34855597 在Swift中,结构体和枚举 ...
- Swift中的Optional类型 (可选类型)与强制解包 ? !
我们在swift的开发中会经常遇见?和! ,理解这两个符号深层次的内容对我们的开发是相当有利的: 目前网上对swift3.0的教程还相当的少,如果去搜索会发现早期的说法,在定义变量的时候,swift是 ...
- Swift中的Void类型与空元祖表达式
可能有不少Swift开发者会忽略这么一个细节:在Swift中,Void类型其实是一个别名类型,而其真正的类型为(),即一个空元祖(empty tuple)! 这种语言特性给Swift带来了一些比较方便 ...
- swift中的可选类型
可选类型也是Swift语言新添加的对象.主要是为了解决对象变量或常量为空的情况.在前面定义的变量和常量都不能为空.里面必须要有值. Swift中的可选类型则允许变量(常量)中没有值(被设为nil).要 ...
- Swift 中的指针使用
SWIFT 中 指针被映射为泛型 UnsafePointer<T> UnsafeMutablePointer<T> 表示一组连续数据指针的 UnsafeBufferPoint ...
- Swift中关于任意类型的数组
在Objc中你是不可以把一个非对象类型放入数组的,你必须将其"封箱",然后再放入数组. 在Swift中你可将非对象类型轻松放入数组: let ary = [1,2,3] 你可以明确 ...
- Swift中的集合类型
一.引子: 在2014年10月TIOBE编程语言排行榜中,Swift位居第18位,从2014WWDC发布会首次公布至今不到半年时间,swift一直受到编程人 员的追捧,其热衷程度并不亚于当红巨星Tay ...
- vector 对象中存放指针类型数据
<<C++ Primer>> 第四版Exercise Section 5.6 的5.1.6 有一道题是这样的:编写程序定义一个vector对象,其每个元素都是指向string类 ...
随机推荐
- bzoj1211-树的计数
题意 给出 \(n\) 和长度为 \(n\) 的数列 \(d\) 表示每个点的度数,问有多少颗满足要求的树. 分析 这题是prufer编码的应用. prufer编码是对一个带标号无根树的刻画,生成方式 ...
- poj3107 Godfather 求树的重心
Description Last years Chicago was full of gangster fights and strange murders. The chief of the pol ...
- 基于三个kinect的人体建模
单个kinect的人体重建,在Kinect SDK 1.8中,Kinect Fusion的效果已经很不错了.其缺点显而易见,一是扫描时间长,重建对象也需要长时间保持静态:二是需要人体或者kine ...
- 20165218 实验二 Java面向对象程序设计
实验二 Java面向对象程序设计 课程:java程序设计 姓名:赵冰雨 学号:20165218 指导教师:娄嘉鹏 实验日期:2018.4.16 实验密级:Java开发环境的熟悉 实验内容.步骤与体会: ...
- 【Python3的进制扫盲】
一.进制 1.进制简介 进制就是进位制,是人们规定的一种进位方法.计算机底层的数据运算和存储都是二进制数据.计算机语言就是二进制,计算机能直接识别二进制数据,其它数据都不能直接识别. 2.常用进制 对 ...
- bzoj1912【Apio2010】patrol 巡逻
题解: 显然需要分类讨论了,首先理解k==0即原图时按照dfs序来说 , 每条边至少走两次: k==1,相当于可以省去dfs回溯时第二次走过某条路径的浪费,所以答案是k==0的答案-直径 : k==2 ...
- Windows10实用技巧-固定快捷方式到磁贴菜单方式
快捷方式固定到磁贴 Win10的开始菜单中的磁贴功能比较不错,可以在不清理桌面上其他软件的情况下直接唤醒需要的应用. 但是比较麻烦的是一些应用或快捷方式并不能直接固定到上面. 后来发现所有Windo ...
- bzoj 2530 [Poi2011]Party 构造
2530: [Poi2011]Party Time Limit: 10 Sec Memory Limit: 128 MBSec Special JudgeSubmit: 364 Solved: ...
- re正则模块
1.正则表达式的常用符号 '.' 默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行 '^' 匹配字符开头,若指定flags MULTILINE,这种也可以匹配上 ...
- 「Python」5个开源项目
1-OpenAI universe Universe是一个能在世界上所有的游戏.网站和其他应用中,衡量和训练AI通用智能的软件平台. Universe,AI代理通过称为虚拟网络计算或VNC发送模拟的鼠 ...